using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;

namespace ETC_App1
{
    public partial class Form2 : Form
    {
        private string Imgs_path = "";
        private string Xmls_path = "";
        private XmlLable xmlLable = new XmlLable();
        private List<BndBox> bndBoxes= new List<BndBox>();
        //private Form ROI { get; set; }

        public Form2()
        {
            InitializeComponent();
        }

        public Form2(string[] files) : this()
        {
            listBox1.Items.AddRange(files);
        }

        bool IsToForm1 = false;
        private void button9_Click(object sender, EventArgs e)
        {
            IsToForm1 = true;
            this.Close();
        }


        private void Form2_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (IsToForm1)
            {
                this.DialogResult = DialogResult.Yes;
            }
            else
            {
                this.DialogResult = DialogResult.No;
            }
        }

        private void img_path_btn_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog path = new FolderBrowserDialog();
            path.ShowDialog();
            Imgs_path=path.SelectedPath;

            if (!string.IsNullOrEmpty(Imgs_path)) { 
                DirectoryInfo dir = new DirectoryInfo(@Imgs_path);

                foreach (FileInfo dChild in dir.GetFiles("*.jpg"))
                {
                    this.listBox1.Items.Add("=> "+Path.Combine(Imgs_path,dChild.Name));                
                }
                foreach (FileInfo dChild in dir.GetFiles("*.png"))
                {
                    this.listBox1.Items.Add("=> " + Path.Combine(Imgs_path,dChild.Name));
                }
                if (listBox1.Items.Count > 0)
                {
                    listBox1.SetSelected(0, true);
                    string img = listBox1.SelectedItem.ToString().Remove(0,3);
                    Bitmap bitmap = new Bitmap(img);
                    pictureBox1.Image = bitmap;
                    FreshImg(img);
                }
            }
        }
        private void xml_path_btn_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog path = new FolderBrowserDialog();
            path.ShowDialog();
            Xmls_path = path.SelectedPath;
        }

        double rate;
        int black_left_width;
        int black_top_height;
        private void FreshImg(string img)
        {
            Now_selected = -1;
            int originalWidth = this.pictureBox1.Image.Width;
            int originalHeight = this.pictureBox1.Image.Height;

            PropertyInfo rectangleProperty = this.pictureBox1.GetType().GetProperty("ImageRectangle", BindingFlags.Instance | BindingFlags.NonPublic);
            Rectangle rectangle = (Rectangle)rectangleProperty.GetValue(this.pictureBox1, null);

            int currentWidth = rectangle.Width;
            int currentHeight = rectangle.Height;

            rate = (double)currentHeight / (double)originalHeight;

            black_left_width = (currentWidth == this.pictureBox1.Width) ? 0 : (this.pictureBox1.Width - currentWidth) / 2;
            black_top_height = (currentHeight == this.pictureBox1.Height) ? 0 : (this.pictureBox1.Height - currentHeight) / 2;

            this.xmlLable = new XmlLable();
            foreach(BndBox box in bndBoxes)
            {
                box.Dispose();
            }
            this.bndBoxes = new List<BndBox>();
            checkedListBox1.Items.Clear();

            
            string xml = Path.GetFileName(img);
            xmlLable.Filename = xml;
            xmlLable.Size.Width = originalWidth.ToString();
            xmlLable.Size.Height = originalHeight.ToString();
            xmlLable.Size.Depth = "1";
            if (String.IsNullOrEmpty(Xmls_path))
            {
                MessageBox.Show("請選存放標記目錄", "系統提示", MessageBoxButtons.OK);
                xml_path_btn.PerformClick();
            }
            else
            {
                xml = Path.Combine(Xmls_path, xml.Replace(".jpg", ".xml").Replace(".png", ".xml"));
                if (File.Exists(xml))
                {
                    ReadEixistTree(xml);
                }
            }          
        }
        private void Form2_KeyDown(object sender, KeyEventArgs e)
        {
            if (listBox1.Items.Count <= 0)
            {
                MessageBox.Show("請選則有包含圖片的目錄", "系統提示", MessageBoxButtons.OK);
                img_path_btn.PerformClick();
            }
            else if (e.KeyCode == Keys.D) //下一張按鈕
            {
                if (listBox1.Items.Count>0)
                {
                    if (listBox1.Items.Count > listBox1.SelectedIndex + 1)
                    {
                        listBox1.SetSelected(listBox1.SelectedIndex+1 , true);
                    }
                }
            }
            else if (e.KeyCode == Keys.A) //上一張按鈕
            {
                if (listBox1.Items.Count > 0)
                {
                    if (0 <= listBox1.SelectedIndex -1)
                    {
                        listBox1.SetSelected(listBox1.SelectedIndex - 1, true);
                    }
                }
            }
            else if (e.Control && e.KeyCode == Keys.S) //儲存按鈕
            {
                string path =Application.StartupPath;
                string save_path = Path.Combine(Xmls_path,xmlLable.Filename.Replace(".jpg", ".xml").Replace(".png", ".xml"));
                CreateXmlTree(path+@"\form2_config\Eample.xml", save_path);
            }
            else if (e.Control && e.KeyCode == Keys.W) //創建區塊 按鈕
            {
                if (checkBox1.Checked && !String.IsNullOrWhiteSpace(textBox1.Text))
                    newBndbox(0, textBox1.Text);
                else
                    ShowForm3();

                if (xmlLable.Object.Count > 0)
                {
                    temp_n = xmlLable.Object[xmlLable.Object.Count - 1].Name;
                    temp_x1 = Convert.ToInt32(xmlLable.Object[xmlLable.Object.Count - 1].X1);
                    temp_y1 = Convert.ToInt32(xmlLable.Object[xmlLable.Object.Count - 1].Y1);
                    temp_x2 = Convert.ToInt32(xmlLable.Object[xmlLable.Object.Count - 1].X2);
                    temp_y2 = Convert.ToInt32(xmlLable.Object[xmlLable.Object.Count - 1].Y2);
                }
            }
            else if (e.Control && e.KeyCode == Keys.E) //沿用區塊 按鈕
            {
                if (!String.IsNullOrEmpty(temp_n))
                {
                    if (checkBox1.Checked && !String.IsNullOrWhiteSpace(textBox1.Text))
                        newBndbox(0, textBox1.Text, temp_x1, temp_y1, temp_x2 - temp_x1, temp_y2 - temp_y1);
                    else
                        newBndbox(0, temp_n, temp_x1, temp_y1, temp_x2- temp_x1, temp_y2- temp_y1);
                }
            }
            else if (e.KeyCode == Keys.Delete)
            {
                if (Now_selected >= 0)
                {
                    for (int i= Now_selected+1;i < bndBoxes.Count;i++)
                    {
                        bndBoxes[i].Num=i-1;
                    }
                    bndBoxes[Now_selected].Dispose();
                    bndBoxes.RemoveAt(Now_selected);
                    xmlLable.Object.RemoveAt(Now_selected);
                    ProcessCombobox(-1);
                }                
                Now_selected = -1;
            }
        }
        private string temp_n;
        private int temp_x1;
        private int temp_y1;
        private int temp_x2;
        private int temp_y2;

        public void CreateXmlTree(string src_path,string save_path)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(src_path);

            List<XmlLableObject>obj = xmlLable.Object;

            XmlNode filename_node = doc.DocumentElement.SelectSingleNode("filename"); // filename 節點
            if (filename_node.LastChild == null)
                filename_node.AppendChild(doc.CreateTextNode(xmlLable.Filename));
            else
                filename_node.ReplaceChild(doc.CreateTextNode(xmlLable.Filename), filename_node.LastChild);

            XmlNode width_node = doc.DocumentElement.SelectSingleNode("size").SelectSingleNode("width"); // width 節點
            if (width_node.LastChild == null)
                width_node.AppendChild(doc.CreateTextNode(xmlLable.Size.Width));
            else
                width_node.ReplaceChild(doc.CreateTextNode(xmlLable.Size.Width), width_node.LastChild);

            XmlNode height_node = doc.DocumentElement.SelectSingleNode("size").SelectSingleNode("height"); // height 節點
            if (height_node.LastChild == null)
                height_node.AppendChild(doc.CreateTextNode(xmlLable.Size.Height));
            else
                height_node.ReplaceChild(doc.CreateTextNode(xmlLable.Size.Height), height_node.LastChild);

            XmlNode depth_node = doc.DocumentElement.SelectSingleNode("size").SelectSingleNode("depth"); // depth 節點
            if (depth_node.LastChild == null)
                depth_node.AppendChild(doc.CreateTextNode(xmlLable.Size.Depth));
            else
                depth_node.ReplaceChild(doc.CreateTextNode(xmlLable.Size.Depth), depth_node.LastChild);

            XmlNode newobj;            
            for (int i = 0; i < obj.Count; i++)  // object 節點
            {
                if (i != 0)
                {
                    newobj = doc.ImportNode(doc.DocumentElement.SelectSingleNode("object"), true);
                    doc.DocumentElement.AppendChild(newobj);
                }
                else
                    newobj = doc.DocumentElement.SelectSingleNode("object");

                XmlNode name_node = newobj.SelectSingleNode("name");
                if (name_node.LastChild == null)
                    name_node.AppendChild(doc.CreateTextNode(obj[i].Name));
                else
                    name_node.ReplaceChild(doc.CreateTextNode(obj[i].Name), name_node.LastChild);// 修改節點

                
                XmlNode x1_node = newobj.SelectSingleNode("bndbox").SelectSingleNode("xmin");
                if (x1_node.LastChild == null)
                    x1_node.AppendChild(doc.CreateTextNode(obj[i].X1));
                else
                    x1_node.ReplaceChild(doc.CreateTextNode(obj[i].X1), x1_node.LastChild);// 修改節點


                XmlNode y1_node = newobj.SelectSingleNode("bndbox").SelectSingleNode("ymin");
                if(y1_node.LastChild==null)
                    y1_node.AppendChild(doc.CreateTextNode(obj[i].Y1));
                else
                    y1_node.ReplaceChild(doc.CreateTextNode(obj[i].Y1), y1_node.LastChild);// 修改節點

                XmlNode x2_node = newobj.SelectSingleNode("bndbox").SelectSingleNode("xmax");
                if (x2_node.LastChild == null)
                    x2_node.AppendChild(doc.CreateTextNode(obj[i].X2));
                else
                    x2_node.ReplaceChild(doc.CreateTextNode(obj[i].X2), x2_node.LastChild);// 修改節點

                XmlNode y2_node = newobj.SelectSingleNode("bndbox").SelectSingleNode("ymax");
                if(y2_node.LastChild == null)
                    y2_node.AppendChild(doc.CreateTextNode(obj[i].Y2));
                else
                    y2_node.ReplaceChild(doc.CreateTextNode(obj[i].Y2), y2_node.LastChild);// 修改節點
            }
            doc.Save(save_path);
        }
        
        private void ReadEixistTree(string src_path) 
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(src_path);

            XmlNodeList newobj = doc.DocumentElement.SelectNodes("object");
            
            for (int i =0; i < newobj.Count;i++)
            {
                string name = newobj[i].SelectSingleNode("name").LastChild.OuterXml;
                int x1 = Convert.ToInt32(newobj[i].SelectSingleNode("bndbox").SelectSingleNode("xmin").LastChild.OuterXml);
                int y1 = Convert.ToInt32(newobj[i].SelectSingleNode("bndbox").SelectSingleNode("ymin").LastChild.OuterXml);
                int x2 = Convert.ToInt32(newobj[i].SelectSingleNode("bndbox").SelectSingleNode("xmax").LastChild.OuterXml);
                int y2 = Convert.ToInt32(newobj[i].SelectSingleNode("bndbox").SelectSingleNode("ymax").LastChild.OuterXml);
                newBndbox(-1, name, x1, y1, x2 - x1, y2 - y1);
            }
        }

        public void ProcessCombobox(int index)
        {
            List<XmlLableObject> objs = xmlLable.Object;

            if (index < 0)
            {
                checkedListBox1.Items.Clear();
                foreach (XmlLableObject obj in objs)
                {
                    string temp = String.Format("{0}: {1},{2},{3},{4}", obj.Name, obj.X1, obj.Y1, obj.X2, obj.Y2);

                    checkedListBox1.Items.Add(temp);
                    checkedListBox1.SetItemChecked(checkedListBox1.Items.IndexOf(temp), true);
                }
            }
            else
            {
                XmlLableObject obj=objs[index];
                string temp = String.Format("{0}: {1},{2},{3},{4}", obj.Name, obj.X1, obj.Y1, obj.X2, obj.Y2);
                checkedListBox1.Items[index] = temp;
                checkedListBox1.SetItemChecked(checkedListBox1.Items.IndexOf(temp), true);
            }
        }

        public void newBndbox(int move = -1, string name = "A", int x=300 ,int y=156,int w=300 ,int h=208)
        {
            if (move >= 0)
                move = xmlLable.Object.Count - 1 >= 0 ? xmlLable.Object.Count : 0;
            else
                move = 0;
            int mapping_x=(int)Math.Round(((x+move*10) * rate) + black_left_width, 0, MidpointRounding.AwayFromZero);
            int mapping_y = (int)Math.Round((y * rate) + black_top_height, 0, MidpointRounding.AwayFromZero);
            int mapping_w = (int)Math.Round((w * rate) , 0, MidpointRounding.AwayFromZero);
            int mapping_h= (int)Math.Round((h * rate), 0, MidpointRounding.AwayFromZero);
            Point pp = new Point(mapping_x, mapping_y);
            Size ss = new Size(mapping_w, mapping_h);
            BndBox box = new BndBox(pp, ss, xmlLable.Object.Count-1 >=0 ? xmlLable.Object.Count : 0);
            box.Paint += Bndbox_GotFocus;
            box.MouseClick += Box_MouseClick;
            box.DoubleClick += checkedListBox1_DoubleClick;
            Controls.Add(box);
            box.Parent = pictureBox1;
            bndBoxes.Add(box);
            box.BringToFront();

            string x1 = Math.Round((box.Left - black_left_width) / rate, 0, MidpointRounding.AwayFromZero).ToString();
            string y1 = Math.Round((box.Top - black_top_height) / rate, 0, MidpointRounding.AwayFromZero).ToString();
            string x2 = Math.Round((box.Left - black_left_width + box.Width) / rate, 0, MidpointRounding.AwayFromZero).ToString();
            string y2 = Math.Round((box.Top - black_top_height + box.Height) / rate, 0, MidpointRounding.AwayFromZero).ToString();

            XmlLableObject obj = new XmlLableObject(name, x1, y1, x2, y2);
            xmlLable.Object.Add(obj);
            ProcessCombobox(-1);
        }

        int Now_selected=-1;
        private void Box_MouseClick(object sender, MouseEventArgs e)
        {
            if (checkedListBox1.Items.Count > 0)
            {
                switch (sender)
                {
                    case BndBox sneder:
                        BndBox box = (BndBox)sender;
                        Now_selected = box.Num;
                        break;
                    case CheckedListBox sender2:
                        Now_selected = sender2.SelectedIndex;
                        break;
                }
                if (Now_selected>=0)
                    checkedListBox1.SetSelected(Now_selected, true);
            }
        }

        private void Bndbox_GotFocus(Object sender , EventArgs e)
        {
            BndBox box = (BndBox)sender;
            string x1 = Math.Round((box.Left - black_left_width) / rate, 0, MidpointRounding.AwayFromZero).ToString();
            string y1 = Math.Round((box.Top - black_top_height) / rate, 0, MidpointRounding.AwayFromZero).ToString();
            string x2 = Math.Round((box.Left - black_left_width + box.Width) / rate, 0, MidpointRounding.AwayFromZero).ToString();
            string y2 = Math.Round((box.Top - black_top_height + box.Height) / rate, 0, MidpointRounding.AwayFromZero).ToString();
            xmlLable.Object[box.Num].modifie(x1, y1, x2, y2);
            ProcessCombobox(box.Num);
        }

        private bool fastkey = false;
        private void ShowForm3(string name="")
        {
            Form3 form3 = new Form3(fastkey,name);
            form3.Focus();
            switch (form3.ShowDialog(this))
            {
                case DialogResult.Yes:
                    fastkey = form3.fastkey;
                    this.Show();
                    break;
                case DialogResult.No:
                    this.Close();
                    break;
                default:
                    break;
            }
            if (!String.IsNullOrWhiteSpace(form3.Label))
            {
                if (String.IsNullOrEmpty(name))
                    newBndbox(0, form3.Label);
                else
                {
                    xmlLable.Object[Now_selected].Name = form3.Label;
                    ProcessCombobox(Now_selected);
                }
            }            
        }

        private void checkedListBox1_DoubleClick(object sender, EventArgs e)
        {
            if (checkedListBox1.Items.Count > 0)
            {
                if (Now_selected>=0)
                    ShowForm3(xmlLable.Object[Now_selected].Name);
            }
        }

        private void button8_Click(object sender, EventArgs e)
        {
            if (checkedListBox1.Items.Count > 0)
            {
                if (Now_selected >= 0)
                    ShowForm3(xmlLable.Object[Now_selected].Name);
            }
        }

        private void listBox1_SelectedValueChanged(object sender, EventArgs e)
        {
            string img = listBox1.SelectedItem.ToString().Remove(0, 3);
            Bitmap bitmap = new Bitmap(img);
            pictureBox1.Image = bitmap;
            FreshImg(img);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (listBox1.Items.Count > 0)
            {
                if (listBox1.Items.Count > listBox1.SelectedIndex + 1)
                {
                    listBox1.SetSelected(listBox1.SelectedIndex + 1, true);
                }
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            if (listBox1.Items.Count > 0)
            {
                if (0 <= listBox1.SelectedIndex - 1)
                {
                    listBox1.SetSelected(listBox1.SelectedIndex - 1, true);
                }
            }
        }

        private void button7_Click(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(temp_n))
            {
                if (checkBox1.Checked && !String.IsNullOrWhiteSpace(textBox1.Text))
                    newBndbox(0, textBox1.Text, temp_x1, temp_y1, temp_x2 - temp_x1, temp_y2 - temp_y1);
                else
                    newBndbox(0, temp_n, temp_x1, temp_y1, temp_x2 - temp_x1, temp_y2 - temp_y1);
            }
        }
    }
}
