using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Net;
using System.Security.Cryptography;

namespace KNLib
{
    internal class Bridge
    {
        private Stream output, input;

        public Bridge()
        {
            Splash splash = new Splash();
            splash.Show();
            String host = "http://knlibupdate.googlecode.com/files/";
            String path = "applet.jar";
            WebClient client = new WebClient();

            try
            {
                if (!File.Exists(path) || !md5(path).Equals(client.DownloadString(String.Format("{0}md5.txt", host))))
                {
                    client.DownloadFile(String.Format("{0}{1}", host, path), path);
                }
            }
            catch (WebException)
            {
            }

            splash.Dispose();
            Process proc = new Process();
            proc.StartInfo.FileName = "javaw";
            proc.StartInfo.Arguments = String.Format("-cp {0} Bridge", path);
            proc.StartInfo.RedirectStandardInput = true;
            proc.StartInfo.RedirectStandardOutput = true;
            proc.StartInfo.UseShellExecute = false;
            proc.Start();

            output = proc.StandardInput.BaseStream;
            input = proc.StandardOutput.BaseStream;
        }

        private String md5(String path)
        {
            FileStream file = File.OpenRead(path);
            byte[] hash = new MD5CryptoServiceProvider().ComputeHash(file);
            file.Close();
            return BitConverter.ToString(hash).Replace("-", "").ToLower();
        }

        public byte[] Parse(byte action, byte[] buffer)
        {
            output.WriteByte(action);
            WriteInt(buffer.Length);
            output.Write(buffer, 0, buffer.Length);
            output.Flush();

            return Read(ReadInt());
        }

        private void WriteInt(int value)
        {
            for (int i = 0; i < 4; i++)
            {
                output.WriteByte((byte)(value >> (3 - i) * 8));
            }
        }

        private int ReadInt()
        {
            int value = 0;

            for (int i = 0; i < 4; i++)
            {
                value += input.ReadByte() << (3 - i) * 8;
            }

            return value;
        }

        private byte[] Read(int length)
        {
            byte[] buffer = new byte[length];

            for (int i = 0; i < length; i++)
            {
                buffer[i] = (byte)input.ReadByte();
            }

            return buffer;
        }
    }
}
