package xyz.brysonsteck.ServerCraft.server

import java.io.*;
import java.net.*;
import java.util.*;
import javax.net.ssl.HttpsURLConnection

class Download: Runnable {
  public enum class Status {
    DOWNLOADING, PAUSED, COMPLETE, CANCELLED, ERROR
  }
  public var size: Int
  public var downloaded: Int
  public var contentLength: Int
  public var status: Status

  private final val MAX_BUFFER_SIZE: Number = 1024

  private var url: URL
  private var dir: String

  constructor (url: URL, dir: String) {
    this.url = url
    this.dir = dir
    size = -1
    downloaded = 0
    status = Status.DOWNLOADING
    contentLength = 1
  }

  public fun start() {
    val thread = Thread(this)
    thread.start()
  }

  private fun getFilename(url: URL): String {
    val filename = url.getFile()
    return filename.substring(filename.lastIndexOf('/') + 1)
  }

  override fun run() { 
    var stream: InputStream? = null
    var file: RandomAccessFile? = null

    try {
      // Open connection to URL.
      var connection = url.openConnection() as HttpsURLConnection;

      // Specify what portion of file to download.
      connection.setRequestProperty("Range", "bytes=" + downloaded + "-");

      // Connect to server.
      connection.connect();

      // Make sure response code is in the 200 range.
      if (connection.responseCode / 100 != 2) {
        println(connection.responseCode)
        status = Status.ERROR
      }

      // Check for valid content length.
      contentLength = connection.getContentLength();
      if (contentLength < 1) {
        println(connection.getContentLength())
        status = Status.ERROR
      }

      /* Set the size for this download if it
        hasn't been already set. */
      if (size == -1) {
        size = contentLength;
      }

      // Open file and seek to the end of it.
      file = RandomAccessFile(dir + getFilename(url), "rw");
      file.seek(downloaded.toLong());

      stream = connection.getInputStream();
      while (status == Status.DOWNLOADING) {
        /* Size buffer according to how much of the
          file is left to download. */
        val buffer: ByteArray;
        if (size - downloaded > MAX_BUFFER_SIZE as Int) {
          buffer = ByteArray(MAX_BUFFER_SIZE)
        } else {
          buffer = ByteArray(size - downloaded);
        }

        // Read from server into buffer.
        val read = stream.read(buffer);
        if (read == -1)
          break;

        // Write buffer to file.
        file.write(buffer, 0, read);
        downloaded += read;
      }

      /* Change status to complete if this point was
          reached because downloading has finished. */
      if (status == Status.DOWNLOADING) {
          status = Status.COMPLETE;
      }
    } catch (e: Exception) {
      println(e)
      status = Status.ERROR
    } finally {
        // Close file.
        if (file != null) {
            try {
                file.close();
            } catch (e: Exception) {}
        }

        // Close connection to server.
        if (stream != null) {
            try {
                stream.close();
            } catch (e: Exception) {}
        }
    }
  }
}
