00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 package com.realtime.crossfire.jxclient.faces;
00023
00024 import java.nio.ByteBuffer;
00025 import java.util.HashMap;
00026 import java.util.LinkedList;
00027 import java.util.List;
00028 import java.util.Map;
00029 import javax.swing.ImageIcon;
00030 import org.jetbrains.annotations.NotNull;
00031
00037 public class AskfaceFaceQueue extends AbstractFaceQueue {
00038
00044 private static final int CONCURRENT_ASKFACE_COMMANDS = 8;
00045
00049 @NotNull
00050 private final Object sync = new Object();
00051
00055 @NotNull
00056 private final AskfaceQueue askfaceQueue;
00057
00063 @NotNull
00064 private final Map<Integer, Face> pendingAskfaces = new HashMap<Integer, Face>();
00065
00070 @NotNull
00071 private final Map<Integer, Face> pendingFaces = new HashMap<Integer, Face>();
00072
00076 @NotNull
00077 private final List<Face> pendingFacesQueue = new LinkedList<Face>();
00078
00084 public AskfaceFaceQueue(@NotNull final AskfaceQueue askfaceQueue) {
00085 this.askfaceQueue = askfaceQueue;
00086 }
00087
00091 @Override
00092 public void reset() {
00093 synchronized (sync) {
00094 pendingAskfaces.clear();
00095 pendingFaces.clear();
00096 pendingFacesQueue.clear();
00097 }
00098 }
00099
00103 @Override
00104 public void loadFace(@NotNull final Face face) {
00105 final int faceNum = face.getFaceNum();
00106 if (faceNum <= 0 || faceNum > 65535) {
00107 fireFaceFailed(face);
00108 return;
00109 }
00110
00111 final Integer faceObject = faceNum;
00112 synchronized (sync) {
00113 if (pendingFaces.put(faceObject, face) != null) {
00114
00115 pendingFacesQueue.remove(face);
00116 pendingFacesQueue.add(0, face);
00117 return;
00118 }
00119 pendingFacesQueue.add(0, face);
00120
00121 sendAskface();
00122 }
00123 }
00124
00128 private void sendAskface() {
00129 for (final Face face : pendingFacesQueue) {
00130 if (pendingAskfaces.size() >= CONCURRENT_ASKFACE_COMMANDS) {
00131 break;
00132 }
00133
00134 final int faceNum = face.getFaceNum();
00135 if (pendingAskfaces.put(faceNum, face) == null) {
00136 askfaceQueue.sendAskface(faceNum);
00137 }
00138 }
00139 }
00140
00148 public void faceReceived(final int faceNum, final int faceSetNum, @NotNull final ByteBuffer packet) {
00149 final Integer faceObject = faceNum;
00150 synchronized (sync) {
00151 final Face face = pendingAskfaces.remove(faceObject);
00152 if (face == null) {
00153 System.err.println("received unexpected image for face "+faceNum);
00154 } else {
00155 if (pendingFaces.remove(faceObject) != face) {
00156 assert false;
00157 }
00158 if (!pendingFacesQueue.remove(face)) {
00159 assert false;
00160 }
00161
00162 final byte[] data = new byte[packet.remaining()];
00163 packet.get(data);
00164 processFaceData(face, data);
00165 }
00166 sendAskface();
00167 }
00168 }
00169
00175 private void processFaceData(@NotNull final Face face, @NotNull final byte[] data) {
00176 final ImageIcon originalImageIcon;
00177 try {
00178 originalImageIcon = new ImageIcon(data);
00179 } catch (final IllegalArgumentException ex) {
00180 System.err.println("Invalid .png data for face "+face+": "+ex.getMessage());
00181 return;
00182 }
00183
00184 if (originalImageIcon.getIconWidth() <= 0 || originalImageIcon.getIconHeight() <= 0) {
00185 fireFaceFailed(face);
00186 return;
00187 }
00188
00189 fireFaceLoaded(face, FaceImagesUtils.newFaceImages(originalImageIcon));
00190 }
00191
00192 }