using System;
using System.IO;
using System.Text;
using System.Data;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace CSGBuilder {

    public partial class MainForm : Form {

        public static bool Saved = true;
        public static string FileName = "untitled.csg";

        private static Solid waiting = null;

        public MainForm() {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
        }

        public void SetSaved(bool value) {
            Saved = value;
            if (!Saved) this.Text = FileName + "* - CSGBuilder";
            else this.Text = FileName + " - CSGBuilder";
            Refresh();
        }

        #region File menü
        private void miNew_Click(object sender, EventArgs e) {
            if (!Saved) {
                DialogResult d = MessageBox.Show("Do you want to save your model?", "CSGBuilder",
                    MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                if (d == DialogResult.Yes) {
                    miSave.PerformClick();
                } else if (d == DialogResult.Cancel)
                    return;
            }
            for (int i = this.MdiChildren.Length - 1; i >= 0; i--)
                this.MdiChildren[i].Dispose();
            FileName = "untitled.csg";
            SetSaved(true);
        }

        private void miOpen_Click(object sender, EventArgs e) {
            if (!Saved) {
                DialogResult d = MessageBox.Show("Do you want to save your model?", "CSGBuilder",
                    MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                if (d == DialogResult.Yes) {
                    miSave.PerformClick();
                } else if (d == DialogResult.Cancel)
                    return;
            }
            ofDialog.Filter = "CSG Files (*.csg) | *.csg";
            if (ofDialog.ShowDialog() == DialogResult.Cancel) return;
            Stream s = File.Open(ofDialog.FileName, FileMode.Open);
            BinaryFormatter b = new BinaryFormatter();
            List<SolidForm> sf = (List<SolidForm>)b.Deserialize(s);
            for (int i = 0; i < sf.Count; i++) {
                sf[i].MdiParent = this;
                sf[i].Show();
            }
            s.Close();
            FileName = ofDialog.FileName;
            SetSaved(true);
        }

        private void miSave_Click(object sender, EventArgs e) {
            if (FileName == "untitled.csg") miSaveAs.PerformClick();
            else {
                Stream s = File.Open(FileName, FileMode.Create);
                BinaryFormatter b = new BinaryFormatter();
                List<SolidForm> sf = new List<SolidForm>();
                for (int i = 0; i < this.MdiChildren.Length; i++)
                    sf.Add((SolidForm)this.MdiChildren[i]);
                b.Serialize(s, sf);
                s.Close();
                SetSaved(true);
            }
        }

        private void miSaveAs_Click(object sender, EventArgs e) {
            sfDialog.AddExtension = true;
            sfDialog.Filter = "CSG Files (*.csg)|*.csg";
            if (sfDialog.ShowDialog() == DialogResult.Cancel) return;
            Stream s = File.Open(sfDialog.FileName, FileMode.Create);
            BinaryFormatter b = new BinaryFormatter();
            List<SolidForm> sf = new List<SolidForm>();
            for (int i = 0; i < this.MdiChildren.Length; i++)
                sf.Add((SolidForm)this.MdiChildren[i]);
            b.Serialize(s, sf);
            s.Close();
            FileName = sfDialog.FileName;
            SetSaved(true);
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e) {
            if (!Saved) {
                DialogResult d = MessageBox.Show("Do you want to save your model?", "CSGBuilder",
                    MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                if (d == DialogResult.Yes) {
                    miSave.PerformClick();
                } else if (d == DialogResult.Cancel)
                    e.Cancel = true;
            }
        }

        private void miExit_Click(object sender, EventArgs e) {
            Application.Exit();
        }
        #endregion

        #region Solids menü

        private void miCuboid_Click(object sender, EventArgs e) {
            NewCuboid nb = new NewCuboid();
            if (nb.ShowDialog() == DialogResult.OK) {
                Cuboid c = new Cuboid(nb.width, nb.height, nb.depth,
                    (nb.cbCenter.Checked ? null : new Point3D(nb.cx, nb.cy, nb.cz)));
                SolidForm sf = new SolidForm("Cuboid " + Cuboid.counter++, c);
                sf.MdiParent = this;
                SetSaved(false);
                sf.Show();
            }
        }

        private void miEllipsoid_Click(object sender, EventArgs e) {
            NewEllipsoid ns = new NewEllipsoid();
            if (ns.ShowDialog() == DialogResult.OK) {
                Ellipsoid el = new Ellipsoid(ns.radx, ns.rady, ns.radz, ns.hdiv, ns.vdiv,
                    (ns.cbCenter.Checked ? null : new Point3D(ns.cx, ns.cy, ns.cz)));
                SolidForm sf = new SolidForm("Ellipsoid " + Ellipsoid.counter++, el);
                sf.MdiParent = this;
                SetSaved(false);
                sf.Show();
            }
        }

        private void miTorus_Click(object sender, EventArgs e) {
            NewTorus ns = new NewTorus();
            if (ns.ShowDialog() == DialogResult.OK) {
                Torus t = new Torus(ns.irad, ns.mrad, ns.hdiv, ns.vdiv,
                    (ns.cbCenter.Checked ? null : new Point3D(ns.cx, ns.cy, ns.cz)));
                SolidForm sf = new SolidForm("Torus " + Torus.counter++, t);
                sf.MdiParent = this;
                SetSaved(false);
                sf.Show();
            }
        }

        private void miCone_Click(object sender, EventArgs e) {
            NewCone ns = new NewCone();
            if (ns.ShowDialog() == DialogResult.OK) {
                Cone c = new Cone(ns.rad, ns.height, ns.div,
                    (ns.cbCenter.Checked ? null : new Point3D(ns.cx, ns.cy, ns.cz)));
                SolidForm sf = new SolidForm("Cone " + Cone.counter++, c);
                sf.MdiParent = this;
                SetSaved(false);
                sf.Show();
            }
        }

        private void miCylinder_Click(object sender, EventArgs e) {
            NewCylinder ns = new NewCylinder();
            if (ns.ShowDialog() == DialogResult.OK) {
                Cylinder c = new Cylinder(ns.rad, ns.height, ns.div,
                    (ns.cbCenter.Checked ? null : new Point3D(ns.cx, ns.cy, ns.cz)));
                SolidForm sf = new SolidForm("Cylinder " + Cylinder.counter++, c);
                sf.MdiParent = this;
                SetSaved(false);
                sf.Show();
            }
        }

        private void miIcosahedron_Click(object sender, EventArgs e) {
            NewIcosahedron ns = new NewIcosahedron();
            if (ns.ShowDialog() == DialogResult.OK) {
                Icosahedron c = new Icosahedron(ns.edgelen, (ns.cbCenter.Checked ? null : new Point3D(ns.cx, ns.cy, ns.cz)));
                SolidForm sf = new SolidForm("Icosahedron " + Icosahedron.counter++, c);
                sf.MdiParent = this;
                SetSaved(false);
                sf.Show();
            }
        }

        private void miDelete_Click(object sender, EventArgs e) {
            if (this.ActiveMdiChild != null) {
                this.ActiveMdiChild.Dispose();
                SetSaved(false);
            }
        }

        private void miDeleteAll_Click(object sender, EventArgs e) {
            if (this.MdiChildren.Length == 0) return;
            if (MessageBox.Show("Are you sure you want to delete all solid?", "Deleting solids",
                MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) return;
            for (int i = this.MdiChildren.Length - 1; i >= 0; i--)
                this.MdiChildren[i].Dispose();
            SetSaved(false);
        }

        #endregion

        #region Operations menü

        public void ResultCallback() {
            if ((new Preview(waiting)).ShowDialog() == DialogResult.OK) {
                SolidForm sf = new SolidForm("Solid " + Solid.pcounter++, waiting);
                SetSaved(false);
                sf.MdiParent = this;
                sf.Show();
            }
        }

        private void miUnion_Click(object sender, EventArgs e) {
            Union u = new Union();
            foreach (SolidForm sf in this.MdiChildren)
                u.cbSolid1.Items.Add(sf.Text);
            foreach (SolidForm sf in this.MdiChildren)
                u.cbSolid2.Items.Add(sf.Text);
            if (u.ShowDialog() == DialogResult.Cancel) return;
            SolidForm s1 = (SolidForm)this.MdiChildren[u.cbSolid1.SelectedIndex];
            SolidForm s2 = (SolidForm)this.MdiChildren[u.cbSolid2.SelectedIndex];
            ProgressForm pf = new ProgressForm(); pf.Show();
            Thread t = new Thread(delegate() {
                waiting = Operations.Construct("union", s1.getModifiedSolid(), s2.getModifiedSolid(), pf);
                pf.Dispose();
                if (waiting == null) {
                    MessageBox.Show("The operation is aborted or the result is empty set!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                this.Invoke(new MethodInvoker(ResultCallback));
            });
            t.Start();
        }

        private void miIntersect_Click(object sender, EventArgs e) {
            Intersect u = new Intersect();
            foreach (SolidForm sf in this.MdiChildren)
                u.cbSolid1.Items.Add(sf.Text);
            foreach (SolidForm sf in this.MdiChildren)
                u.cbSolid2.Items.Add(sf.Text);
            if (u.ShowDialog() == DialogResult.Cancel) return;
            SolidForm s1 = (SolidForm)this.MdiChildren[u.cbSolid1.SelectedIndex];
            SolidForm s2 = (SolidForm)this.MdiChildren[u.cbSolid2.SelectedIndex];
            ProgressForm pf = new ProgressForm(); pf.Show();
            Thread t = new Thread(delegate() {
                waiting = Operations.Construct("intersection", s1.getModifiedSolid(), s2.getModifiedSolid(), pf);
                pf.Dispose();
                if (waiting == null) {
                    MessageBox.Show("The operation is aborted or the result is empty set!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                this.Invoke(new MethodInvoker(ResultCallback));
            });
            t.Start();
        }

        private void miDifference_Click(object sender, EventArgs e) {
            Difference u = new Difference();
            foreach (SolidForm sf in this.MdiChildren)
                u.cbSolid1.Items.Add(sf.Text);
            foreach (SolidForm sf in this.MdiChildren)
                u.cbSolid2.Items.Add(sf.Text);
            if (u.ShowDialog() == DialogResult.Cancel) return;
            SolidForm s1 = (SolidForm)this.MdiChildren[u.cbSolid1.SelectedIndex];
            SolidForm s2 = (SolidForm)this.MdiChildren[u.cbSolid2.SelectedIndex];
            ProgressForm pf = new ProgressForm(); pf.Show();
            Thread t = new Thread(delegate() {
                waiting = Operations.Construct("difference", s1.getModifiedSolid(), s2.getModifiedSolid(), pf);
                pf.Dispose();
                if (waiting == null) {
                    MessageBox.Show("The operation is aborted or the result is empty set!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                this.Invoke(new MethodInvoker(ResultCallback));
            });
            t.Start();
        }

        #endregion

        #region Window menü
        private void miCascade_Click(object sender, EventArgs e) {
            this.LayoutMdi(MdiLayout.Cascade);
            miCascade.Checked = true;
            miVertical.Checked = false;
            miHorizontal.Checked = false;
            miArrangeIcons.Checked = false;
            this.Refresh();
        }

        private void miVertical_Click(object sender, EventArgs e) {
            this.LayoutMdi(MdiLayout.TileVertical);
            miCascade.Checked = false;
            miVertical.Checked = true;
            miHorizontal.Checked = false;
            miArrangeIcons.Checked = false;
            this.Refresh();
        }

        private void miHorizontal_Click(object sender, EventArgs e) {
            this.LayoutMdi(MdiLayout.TileHorizontal);
            miCascade.Checked = false;
            miVertical.Checked = false;
            miHorizontal.Checked = true;
            miArrangeIcons.Checked = false;
            this.Refresh();
        }

        private void miArrangeIcons_Click(object sender, EventArgs e) {
            this.LayoutMdi(MdiLayout.ArrangeIcons);
            miCascade.Checked = false;
            miVertical.Checked = false;
            miHorizontal.Checked = false;
            miArrangeIcons.Checked = true;
            this.Refresh();
        }
        #endregion

        #region Help menü
        private void miHotkeys_Click(object sender, EventArgs e) {
            (new ShowHotkeys()).ShowDialog();
        }
        private void miAbout_Click(object sender, EventArgs e) {
            (new AboutBox()).ShowDialog();
        }
        #endregion

    }
}