package yecheng;

import org.json.JSONObject;
import yecheng.music.database.Index;
import yecheng.music.database.MysqlDB;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;

import static yecheng.music.database.Index.Hash2id;

/**
 * Created by hsyecheng on 2015/6/16.
 * This is a server providing music recognition service;
 */
@SuppressWarnings("WeakerAccess")
public class Server {
    private final static int port = 1234;

    public static class ServerDataBase{
        class Node{
            int id;
            int time;
        }
        final HashMap<Integer,ArrayList<Node>> Database;
        final HashMap<Long,Integer> hashMap;

        public ServerDataBase() {
            super();
            Database = new HashMap<>(2560000);
            hashMap = new HashMap<>(4000000);

            MysqlDB sqlDB = new MysqlDB();
            ResultSet rs = sqlDB.listAll();

            try {
                while(rs.next()){
                    int hash = rs.getInt(2);
                    int id = rs.getInt(3);
                    int time = rs.getInt(4);
                    Node node = new Node();
                    node.id = id;
                    node.time = time;

                    ArrayList<Node> idList = Database.get(hash);
                    if(idList == null){
                        idList = new ArrayList<>();
                        Database.put(hash,idList);
                    }
                    idList.add(node);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        private long maxId = -1;
        private int maxCount = -1;
        public int search(int[] linkTime,int[] linkHash, @SuppressWarnings("SameParameterValue") int minHit){
            hashMap.clear();
            for(int i = 0; i < linkHash.length; i ++){
                final ArrayList<Node> list = Database.get(linkHash[i]);
                final int time = linkTime[i];
                list.forEach(node -> {
                    long idHash = Index.idHash(node.id, node.time - time);
                    Integer count = hashMap.get(idHash);
                    if(count == null) count = 0;
                    hashMap.put(idHash,count + 1);
                });
            }

            maxId = -1;
            maxCount = -1;

            hashMap.forEach((hash, integer) -> {
                if(integer > minHit && integer > maxCount){
                    maxId = hash;
                    maxCount = integer;
                }
            });

            System.out.println(Hash2id(maxId) + ":" + maxCount);
            return Hash2id(maxId);
        }
    }

    public static void main(String[] arg) {
        System.out.println("Loading Database!");
        ServerDataBase dataBase = new ServerDataBase();
        System.gc();
        System.out.println("Complete!");
        MysqlDB mysqlDB = new MysqlDB();

        try {
            ServerSocket serverSocket = new ServerSocket(port);

            Socket socket;

            while (true) {
                try {
                    socket = serverSocket.accept();

                    InputStream is = socket.getInputStream();
                    ByteBuffer buf = ByteBuffer.allocate(4);
                    byte[] a = new byte[4];
                    //noinspection ResultOfMethodCallIgnored
                    is.read(a);
                    buf.put(a);
                    buf.rewind();
                    int size = buf.getInt();
                    buf.rewind();

                    int[] link = new int[size];
                    int[] time = new int[size];

                    int i = 0;
                    while (is.read(a) != -1) {
                        buf.put(a);
                        buf.rewind();
                        if (i < size) {
                            link[i] = buf.getInt();
                        } else {
                            time[i - size] = buf.getInt();
                        }
                        i++;
                        buf.rewind();
                    }

                    int id = dataBase.search(time, link, 15);
                    JSONObject jsonObject = mysqlDB.getByID(id);
                    PrintWriter writer = new PrintWriter(socket.getOutputStream());
                    if(jsonObject == null)
                        writer.write("");
                    else writer.write(jsonObject.toString());
                    writer.close();
                    System.out.println(jsonObject.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}



@@ -392,16 +392,38 @@
 HashMap;
+%0Aimport java.util.Map;
 %0A%0Aimport
@@ -1703,32 +1703,60 @@
               %7D%0A
+                rs.close();%0A
             %7D ca
@@ -2174,16 +2174,59 @@
 sh%5Bi%5D);%0A
+                if(list == null) continue;%0A
         
@@ -2621,16 +2621,70 @@
  = -1;%0A%0A
+            Map%3CLong,Integer%3E list = new HashMap%3C%3E();%0A
         
@@ -2742,16 +2742,120 @@
       if
+ (integer %3E minHit) %7B%0A                    list.put(hash,integer);%0A                %7D%0A%0A                if 
 (integer
@@ -2886,16 +2886,17 @@
 axCount)
+ 
 %7B%0A      
@@ -4590,17 +4590,17 @@
  link, 1
-5
+8
 );%0A     

fix a bug