private final void passivesRequest() {
   while (true) {
     if (immediateRequestsSent != 0) {
       break;
     }
     if (passiveRequestsSent >= 10) {
       break;
     }
     if (highestPriority == 0) {
       break;
     }
     OnDemandNode onDemandNode;
     synchronized (passiveRequests) {
       onDemandNode = (OnDemandNode) passiveRequests.popTail();
     }
     while (onDemandNode != null) {
       if (filePriorities[onDemandNode.type][onDemandNode.id] != 0) {
         filePriorities[onDemandNode.type][onDemandNode.id] = (byte) 0;
         sentRequests.insertBack(onDemandNode);
         sendRequest(onDemandNode);
         expectData = true;
         if (extrasLoaded < extrasTotal) {
           extrasLoaded++;
         }
         message = "Loading extra files - " + ((extrasLoaded * 100) / extrasTotal) + "%";
         passiveRequestsSent++;
         if (passiveRequestsSent == 10) {
           return;
         }
       }
       synchronized (passiveRequests) {
         onDemandNode = (OnDemandNode) passiveRequests.popTail();
       }
     }
     for (int type = 0; type < 4; type++) {
       byte[] priority = filePriorities[type];
       for (int id = 0; id < priority.length; id++) {
         if (priority[id] == highestPriority) {
           priority[id] = (byte) 0;
           onDemandNode = new OnDemandNode();
           onDemandNode.type = type;
           onDemandNode.id = id;
           onDemandNode.immediate = false;
           sentRequests.insertBack(onDemandNode);
           sendRequest(onDemandNode);
           expectData = true;
           if (extrasLoaded < extrasTotal) {
             extrasLoaded++;
           }
           message = "Loading extra files - " + ((extrasLoaded * 100) / extrasTotal) + "%";
           passiveRequestsSent++;
           if (passiveRequestsSent == 10) {
             return;
           }
         }
       }
     }
     highestPriority--;
   }
 }
 private final void localComplete() {
   OnDemandNode onDemandNode;
   synchronized (wanted) {
     onDemandNode = (OnDemandNode) wanted.popTail();
   }
   while (onDemandNode != null) {
     expectData = true;
     byte[] buffer = null;
     if (client.stores[0] != null) {
       buffer = client.stores[onDemandNode.type + 1].get(onDemandNode.id);
     }
     if (!verify(
         fileVersions[onDemandNode.type][onDemandNode.id],
         fileCrc[onDemandNode.type][onDemandNode.id],
         buffer)) {
       buffer = null;
     }
     synchronized (wanted) {
       if (buffer == null) {
         toRequest.insertBack(onDemandNode);
       } else {
         onDemandNode.buffer = buffer;
         synchronized (completed) {
           completed.insertBack(onDemandNode);
         }
       }
       onDemandNode = (OnDemandNode) wanted.popTail();
     }
   }
 }
 public final void request(int type, int id) {
   if ((type >= 0)
       && (type <= fileVersions.length)
       && (id >= 0)
       && (id <= fileVersions[type].length)
       && (fileVersions[type][id] != 0)) {
     synchronized (immediateRequests) {
       for (OnDemandNode onDemandNode = (OnDemandNode) immediateRequests.reverseGetFirst();
           onDemandNode != null;
           onDemandNode = (OnDemandNode) immediateRequests.reverseGetNext()) {
         if ((onDemandNode.type == type) && (onDemandNode.id == id)) {
           return;
         }
       }
       OnDemandNode ondemandnode = new OnDemandNode();
       ondemandnode.type = type;
       ondemandnode.id = id;
       ondemandnode.immediate = true;
       synchronized (wanted) {
         wanted.insertBack(ondemandnode);
       }
       immediateRequests.insertHead(ondemandnode);
     }
   }
 }
 public final void passiveRequest(int id, int type) {
   if ((client.stores[0] != null)
       && (fileVersions[type][id] != 0)
       && (filePriorities[type][id] != 0)
       && (highestPriority != 0)) {
     OnDemandNode onDemandNode = new OnDemandNode();
     onDemandNode.type = type;
     onDemandNode.id = id;
     onDemandNode.immediate = false;
     synchronized (passiveRequests) {
       passiveRequests.insertBack(onDemandNode);
     }
   }
 }
 public final OnDemandNode next() {
   OnDemandNode onDemandNode;
   synchronized (completed) {
     onDemandNode = (OnDemandNode) completed.popTail();
   }
   if (onDemandNode == null) {
     return null;
   }
   synchronized (immediateRequests) {
     onDemandNode.clear();
   }
   if (onDemandNode.buffer == null) {
     return onDemandNode;
   }
   int offset = 0;
   try {
     GZIPInputStream gzipinputstream =
         new GZIPInputStream(new ByteArrayInputStream(onDemandNode.buffer));
     while (true) {
       if (offset == deflateOut.length) {
         throw new RuntimeException("buffer overflow!");
       }
       int readByte = gzipinputstream.read(deflateOut, offset, deflateOut.length - offset);
       if (readByte == -1) {
         break;
       }
       offset += readByte;
     }
   } catch (IOException ioexception) {
     throw new RuntimeException("error unzipping");
   }
   onDemandNode.buffer = new byte[offset];
   for (int position = 0; position < offset; position++) {
     onDemandNode.buffer[position] = deflateOut[position];
   }
   return onDemandNode;
 }
 private final void handleResp() {
   try {
     int available = inputStream.available();
     if ((toRead == 0) && (available >= 6)) {
       expectData = true;
       for (int i = 0; i < 6; i += inputStream.read(inputBuffer, i, 6 - i)) {;
       }
       int type = inputBuffer[0] & 0xff;
       int id = ((inputBuffer[1] & 0xff) << 8) + (inputBuffer[2] & 0xff);
       int size = ((inputBuffer[3] & 0xff) << 8) + (inputBuffer[4] & 0xff);
       int part = inputBuffer[5] & 0xff;
       onDemandNode = null;
       for (OnDemandNode ondemandnode = (OnDemandNode) sentRequests.getBack();
           ondemandnode != null;
           ondemandnode = (OnDemandNode) sentRequests.getPrevious()) {
         if ((ondemandnode.type == type) && (ondemandnode.id == id)) {
           onDemandNode = ondemandnode;
         }
         if (onDemandNode != null) {
           ondemandnode.cyclesSinceSend = 0;
         }
       }
       if (onDemandNode != null) {
         idleCycles = 0;
         if (size == 0) {
           SignLink.reportError("Rej: " + type + "," + id);
           onDemandNode.buffer = null;
           if (onDemandNode.immediate) {
             synchronized (completed) {
               completed.insertBack(onDemandNode);
             }
           } else {
             onDemandNode.remove();
           }
           onDemandNode = null;
         } else {
           if ((onDemandNode.buffer == null) && (part == 0)) {
             onDemandNode.buffer = new byte[size];
           }
           if ((onDemandNode.buffer == null) && (part != 0)) {
             throw new IOException("missing start of file");
           }
         }
       }
       offset = part * 500;
       toRead = 500;
       if (toRead > (size - (part * 500))) {
         toRead = size - (part * 500);
       }
     }
     if ((toRead <= 0) || (available < toRead)) {
       return;
     }
     expectData = true;
     byte[] buffer = inputBuffer;
     int bufferOffset = 0;
     if (onDemandNode != null) {
       buffer = onDemandNode.buffer;
       bufferOffset = offset;
     }
     for (int i = 0; i < toRead; i += inputStream.read(buffer, i + bufferOffset, toRead - i)) {;
     }
     if (((toRead + offset) >= buffer.length) && (onDemandNode != null)) {
       if (client.stores[0] != null) {
         client.stores[onDemandNode.type + 1].put(buffer.length, buffer, onDemandNode.id);
       }
       if (!onDemandNode.immediate && (onDemandNode.type == 3)) {
         onDemandNode.immediate = true;
         onDemandNode.type = 93;
       }
       if (onDemandNode.immediate) {
         synchronized (completed) {
           completed.insertBack(onDemandNode);
         }
       } else {
         onDemandNode.remove();
       }
     }
     toRead = 0;
   } catch (IOException ioexception) {
     try {
       socket.close();
     } catch (Exception exception) {
       /* empty */
     }
     socket = null;
     inputStream = null;
     outputStream = null;
     toRead = 0;
   }
 }
 @Override
 public final void run() {
   try {
     while (running) {
       cycle++;
       int toWait = 20;
       if ((highestPriority == 0) && (client.stores[0] != null)) {
         toWait = 50;
       }
       Thread.sleep(toWait);
       expectData = true;
       for (int i = 0; i < 100; i++) {
         if (!expectData) {
           break;
         }
         expectData = false;
         localComplete();
         remainingRequest();
         if ((immediateRequestsSent == 0) && (i >= 5)) {
           break;
         }
         passivesRequest();
         if (inputStream != null) {
           handleResp();
         }
       }
       boolean idle = false;
       for (OnDemandNode onDemandNode = (OnDemandNode) sentRequests.getBack();
           onDemandNode != null;
           onDemandNode = (OnDemandNode) sentRequests.getPrevious()) {
         if (onDemandNode.immediate) {
           idle = true;
           onDemandNode.cyclesSinceSend++;
           if (onDemandNode.cyclesSinceSend > 50) {
             onDemandNode.cyclesSinceSend = 0;
             sendRequest(onDemandNode);
           }
         }
       }
       if (!idle) {
         for (OnDemandNode onDemandNode = (OnDemandNode) sentRequests.getBack();
             onDemandNode != null;
             onDemandNode = (OnDemandNode) sentRequests.getPrevious()) {
           idle = true;
           onDemandNode.cyclesSinceSend++;
           if (onDemandNode.cyclesSinceSend > 50) {
             onDemandNode.cyclesSinceSend = 0;
             sendRequest(onDemandNode);
           }
         }
       }
       if (idle) {
         idleCycles++;
         if (idleCycles > 750) {
           socket.close();
           socket = null;
           inputStream = null;
           outputStream = null;
           toRead = 0;
         }
       } else {
         idleCycles = 0;
         message = "";
       }
       if (client.loggedIn
           && (socket != null)
           && (outputStream != null)
           && ((highestPriority > 0) || (client.stores[0] == null))) {
         sinceKeepAlive++;
         if (sinceKeepAlive > 500) {
           sinceKeepAlive = 0;
           inputBuffer[0] = (byte) 0;
           inputBuffer[1] = (byte) 0;
           inputBuffer[2] = (byte) 0;
           inputBuffer[3] = (byte) 10;
           try {
             outputStream.write(inputBuffer, 0, 4);
           } catch (IOException ioexception) {
             idleCycles = 5000;
           }
         }
       }
     }
   } catch (Exception exception) {
     SignLink.reportError("od_ex " + exception);
   }
 }