using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;

namespace 電子文書回覧監視ツール
{
    class recieveprocess {
        Form1 form;
        public recieveprocess(Form1 form) {
            this.form = form;
            setCommentMethod = new DelegatesetComment(setComment);
            replaceCommentMethod = new DelegatereplaceComment(replaceComment);
            setMemoMethod = new DelegatesetMemo(setMemo);
        }

        Queue<string> que = new Queue<string>();
        System.Threading.AutoResetEvent dataEvent = new System.Threading.AutoResetEvent(false);
        IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 0);
        IPAddress[] myIP = Dns.GetHostAddresses(Dns.GetHostName());
        string rcvtext;
        string command;
        System.Threading.Thread thread1;
        bool done;

        public void recieve() {
            thread1 = new System.Threading.Thread(new System.Threading.ThreadStart(this.process1));
            thread1.Start();
            done = false;
            form.udp.MulticastLoopback = true;
            string lastrcvtext = "";
            byte[] bytes = new byte[200];    
            while(!done) {
                    try {
                        groupEP.Address = IPAddress.Any;
                        groupEP.Port = 0;
                        bytes = form.udp.Receive(ref groupEP);//UDP受信
                    }
                    catch(SocketException)// err or listner closeによる例外
                    {
                        continue;
                    }
                    rcvtext = Encoding.UTF8.GetString(bytes, 0, bytes.Length);//コード変換
                    if(OwnMessage(groupEP)) continue;
                    if(rcvtext == lastrcvtext) {
                        continue;
                    }
                    else {
                        lastrcvtext = rcvtext;
                    }
                    System.Threading.Monitor.Enter(que);
                    {
                        que.Enqueue(rcvtext);//キューイング
                        if((bool)activeflag == false) {
                            dataEvent.Set();  //処理スレッド起動
                        }
                    }
                    System.Threading.Monitor.Exit(que);
                }
            
                done = true;
                dataEvent.Set();
                thread1.Join();
        }
        
        //折り返し電文か判定
        private bool OwnMessage(IPEndPoint groupEP) {
            if(groupEP.Port != Form1.watchPort) {
                return false;
            }
            foreach(IPAddress myAdr in myIP) {
                if(groupEP.Address == myAdr) return true;
            }
            return false;
        }
        
        public void recieveclose() {
            done = true;
            form.udp.Close();
        }

        object activeflag = false;
        Dictionary<string, string> Dic = new Dictionary<string, string>();
        void process1() {
            while(!done) {
                System.Threading.Monitor.Enter(que);
                if(que.Count == 0) {
                    activeflag = false;
                    System.Threading.Monitor.Exit(que);
                    dataEvent.WaitOne();
                    activeflag = true;
                    continue;
                }
                else {
                    string rectext = que.Dequeue();
                    System.Threading.Monitor.Exit(que);
                    command = rectext.Split('|')[4];
                    switch(command) {
                        //0日時
                        //1USERID(または氏名)
                        //2PROGRAM区分(WATCH/TRACK)
                        //3version
                        //4COMMAND
                        //5パス(長短)
                        //6文書名
                        //7コメント、メモ
                        //8緊急度
                        case "putdocumentinfo":
                            setComment(rectext.Split('|')[1], rectext.Split('|')[5], rectext.Split('|')[6], rectext.Split('|')[7], rectext.Split('|')[8]);
                            break;
                        case "replacecomment":
                            replaceComment( rectext.Split('|')[5], rectext.Split('|')[6], rectext.Split('|')[7], rectext.Split('|')[8]);
                            break;
                        case "putmemo":
                            setMemo(rectext.Split('|')[5], rectext.Split('|')[6], rectext.Split('|')[7]);
                            break;
                        default:
                            break;
                    }
                    Debug.Write("受信：" + rectext + Environment.NewLine);
                }

            }
        }

        //コメントセット
        DelegatesetComment setCommentMethod;
        void setComment(string trackingperson, string dir, string doc, string comment, string priority) {
            if(this.form.InvokeRequired) {
                object[] args = { trackingperson, dir, doc, comment, priority };
                this.form.BeginInvoke(setCommentMethod, args);  //No Wait
                return;
            }
            List<string> dockinds = new List<string>();
            int i;
            for(i=0; i<this.form.folders.Count; i++){
                if (this.form.folders[i].StartsWith(dir))
                {
                    dockinds.Add(this.form.types[i]); //複数の文書種類(「ｘｘ申請書」と「ｘｘ申請書差し戻し確認中」)にマッチすることを考慮
                }
            }
            foreach (String dockind in dockinds)
            {
                bool find = false;
                for (i = 0; i < this.form.dataSet2.Tables[0].Rows.Count; i++)
                {
                    //lock (form.行Lock)
                    //{
                        if (this.form.dataSet2.Tables[0].Rows[i][1].ToString() == dockind && this.form.dataSet2.Tables[0].Rows[i][2].ToString() == doc)
                        {
                            if(this.form.dataSet2.Tables[0].Rows[i][5].ToString() == "" || this.form.dataSet2.Tables[0].Rows[i][5].ToString() == trackingperson) {
                                //初めての人、または同じ人
                                this.form.dataSet2.Tables[0].Rows[i][3] = comment;
                                if(this.form.dataSet2.Tables[0].Rows[i][4].ToString() != priority) {
                                    this.form.dataSet2.Tables[0].Rows[i][4] = priority;
                                    this.form.タスクバー編集(this.form.dataSet2.Tables[0]);
                                }
                                this.form.dataSet2.Tables[0].Rows[i][5] = trackingperson;
                                find = true; break;
                            }
                        }
                    //}
                }
                if (find) break;
            }
        }

        //コメント置き換え
        DelegatereplaceComment replaceCommentMethod;
        void replaceComment(string dir, string doc, string comment, string priority) {
            if(this.form.InvokeRequired) {
                object[] args = { dir, doc, comment, priority };
                this.form.Invoke(replaceCommentMethod, args);  //No Wait
                return;
            }
            List<string> dockinds = new List<string>();
            int i;
            for(i = 0; i < this.form.folders.Count; i++) {
                if(this.form.folders[i].StartsWith(dir)) {
                    dockinds.Add(this.form.types[i]); //複数の文書種類にマッチすることを考慮
                }
            }
            foreach(String dockind in dockinds) {
                bool find = false;
                for(i = 0; i < this.form.dataSet2.Tables[0].Rows.Count; i++) {
                    //lock(form.行Lock) {
                        if(this.form.dataSet2.Tables[0].Rows[i][1].ToString() == dockind && this.form.dataSet2.Tables[0].Rows[i][2].ToString() == doc) {
                            this.form.dataSet2.Tables[0].Rows[i][3] = comment;
                            if(this.form.dataSet2.Tables[0].Rows[i][4].ToString() != priority) {
                                this.form.dataSet2.Tables[0].Rows[i][4] = priority;
                                this.form.タスクバー編集(this.form.dataSet2.Tables[0]);
                            }
                            find = true; break;
                        }
                    //}
                }
                if(find) break;
            }
            this.form.Refresh();
        }

        //メモ
        DelegatesetMemo setMemoMethod;
        void setMemo(string dir, string doc,  string memo) {
            if(this.form.InvokeRequired) {
                object[] args = {  dir, doc, memo };
                this.form.Invoke(setMemoMethod, args);  //No Wait
                return;
            }
            List<string> dockinds = new List<string>();
            int i;
            for(i = 0; i < this.form.folders.Count; i++) {
                if(this.form.folders[i].StartsWith(dir)) {
                    dockinds.Add(this.form.types[i]); //複数の文書種類にマッチすることを考慮
                }
            }
            foreach(String dockind in dockinds) {
                bool find = false;
                for(i = 0; i < this.form.dataSet2.Tables[0].Rows.Count; i++) {
                    //lock(form.行Lock) {
                        if(this.form.dataSet2.Tables[0].Rows[i][1].ToString() == dockind && this.form.dataSet2.Tables[0].Rows[i][2].ToString() == doc) {
                            this.form.dataSet2.Tables[0].Rows[i][6] = memo;
                            this.form.行に色付け();
                            find = true; break;
                        }
                    //}
                }
                if(find) break;
            }
        }
    }
    delegate void DelegatesetComment(string trackingperson, string dir, string doc, string comment, string priority);  //デリゲート定義(コメントセット）)
    delegate void DelegatereplaceComment(string dir, string doc, string comment, string priority);  //デリゲート定義(コメント置き換え)
    delegate void DelegatesetMemo(string dir, string doc, string memoy);  //デリゲート定義(メモ)

}
