using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using NLog;
using ZeroMQ;
using ZeroMQ.Monitoring;
using System.Threading;
using System.Diagnostics;   // Process
using System.Data.SqlClient;    // SqlCommand

namespace TargetProject
{
    class Program
    {
        static Logger log = LogManager.GetLogger("target_logger");
        static void Main(string[] args)
        {
            String home_path = "C:\\Users\\hwajin\\source\\repos\\SocketTransfer\\TargetProject\\conf\\";
            int chk_num = 0;
            bool is_num = int.TryParse(args[0], out chk_num);
            Console.WriteLine("is_num : " + is_num);

            if(is_num)
            {
                String port = args[0];
                Console.WriteLine("port : " + port);

                // database connection
                DBConnect.DBConnection database_connect = new DBConnect.DBConnection();
                DBConnect.Struct.ConnectStateStc connect_result = database_connect.ConnectDB(home_path);

                if (!connect_result.is_connect)
                {
                    log.Error("database connection fail");
                    return;
                }

                log.Debug("database connection success");
                Console.WriteLine("database connection success");

                // processing socket
                TargetSocket(port, connect_result.connection);
            } else
            {
                Console.WriteLine("incorrect port.");
            }
        }

        public static void TargetSocket(String port, SqlConnection connection)
        {
            try
            {
                List<String> list = new List<String>();
                using (var socket = new ZSocket(ZSocketType.REP))
                {
                    log.Debug("## target socket listen start ##");
                    ProcessDatabase.ProcessDB process_database = new ProcessDatabase.ProcessDB();
                    ProcessDatabase.Struct.DataStc data_struct = new ProcessDatabase.Struct.DataStc();

                    // socket connection
                    String conn = String.Format("tcp://172.16.10.63:{0}", port);
                    socket.Bind(conn);  // connect listener

                    // socket monitor
                    socket.Monitor("inproc://monitor.rep", ZMonitorEvents.AllEvents);
                    Thread socketMonitorThread = new Thread(() => MonitorSocket(socket.Context));
                    socketMonitorThread.Start();
                    
                    while(true)
                    {
                        // socket 연결 후 source process 접속 대기
                        Console.WriteLine("socket connection waiting");
                        Thread.Sleep(2000);
                        
                        using (ZFrame frame = socket.ReceiveFrame()) {
                            // source process 전송 데이터
                            String test = frame.ReadString();
                            //byte[] buffer = frame.Read();

                            //String test = Encoding.Default.GetString(buffer);
                            Console.WriteLine("test :: " + test);
                            list.Add(test);
                            // 넘어온 값을 data_struct에 저장

                            if (!socket.ReceiveMore)
                            {
                                Console.WriteLine("cnt :: " + list.Count);
                                // don't wait 처리
                                // return result to source process
                                for(int i = 0; i< (list.Count-1); i++)
                                {
                                    Console.WriteLine("more :: " + list[i]);
                                    log.Debug("more :: " + list[i]);
                                } for(int i = (list.Count - 1); i< list.Count; i++)
                                {
                                    Console.WriteLine("don't wait :: " + list[i]);
                                    log.Debug("don't wait :: " + list[i]);
                                }

                               socket.Send(new ZFrame("결과 값"), ZSocketFlags.DontWait);

                                // exit process
                                //Process process = Process.GetCurrentProcess();
                                //process.Refresh();
                                //process.Kill();
                            }

                            // create query
                            //ExcuteQuery(connection, data_struct);

                            // return result to source process
                            //ProcessQueryResult();
                        }
                    }
                }

                Thread.Sleep(2000);

                log.Debug("## target socket listen end ##");
            } catch(Exception e)
            {
                log.Error(e.ToString());
            }
        }

        public static void MonitorSocket(ZContext context)
        {
            // monitor 연결하고 event 결과값이 disconnect 이면 종료                                
            ZMonitor monitor = ZMonitor.Create(context, "inproc://monitor.rep");
            monitor.Start();

            monitor.AllEvents += (sender, e) =>
            {
                if (e.Event.Event == ZMonitorEvents.Disconnected)
                {
                    log.Debug("recv socket disconnected");
                }
            };
        }

        public static void ProcessQueryResult()
        {

        }

        public static ProcessDatabase.Struct.ResultStc ExcuteQuery(SqlConnection connection, ProcessDatabase.Struct.DataStc data_struct)
        {
            ProcessDatabase.Struct.ResultStc result_query_struct = new ProcessDatabase.Struct.ResultStc();
            int total_cnt = 0;
            int inum = 0, unum = 0, dnum = 0;
            try
            {
                using (SqlCommand cmd = connection.CreateCommand())
                {
                    String schema = data_struct.schema;
                    String table = data_struct.table;
                    String dml_type = data_struct.dml_type;

                    if (dml_type == "insert")
                    {
                        // insert
                        cmd.CommandText = String.Format("insert into {0}.{1}({2}) values({3})", data_struct.schema, data_struct.table, "", "");
                        inum = cmd.ExecuteNonQuery();
                    } else if (dml_type == "update")
                    {
                        // update
                        cmd.CommandText = String.Format("update {0}.{1} set {2} where {3}", data_struct.schema, data_struct.table, "", "");
                        unum = cmd.ExecuteNonQuery();
                    } else if (dml_type == "delete")
                    {
                        // delete
                        cmd.CommandText = String.Format("delete from {0}.{1} where {2}", data_struct.schema, data_struct.table, "");
                        dnum = cmd.ExecuteNonQuery();
                    }
                }
                total_cnt = inum + unum + dnum;
            } catch(Exception e)
            {
                log.Error(e.ToString());
                return new ProcessDatabase.Struct.ResultStc();
            }
            return result_query_struct;
        }
    }
}
