using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using ImageBlockz.Operations.InOut;
using ImageBlockz.Core;
using ImageBlockz.Operations.Edit;
using ImageBlockz.Api;
using System.ComponentModel;

namespace ImageBlockz.Gui
{
    public partial class SequenceGui : UserControl
    {
        private int lastRowClicked;

        private BlockzModel model = new BlockzModel();

        [Browsable(false)]
        public MainWindow MainWindow
        {
            get;
            set;
        }

        private EmptyBlock emptyFilterBlock;

        [Browsable(false)]
        public Sequence Sequence
        {
            get
            {
                return model.Sequence;
            }
            set
            {
                model.Sequence = value;
                GenerateBlockz();
            }
        }

        public SequenceGui()
        {
            InitializeComponent();

            foreach (OperationInfo info in ControlFactory.GetDefaultFactory().OperationInfos)
            {
                if (info.MenuPath == null)
                {
                    continue;
                }

                OperationMenuItem item = BuildMenuPath.BuildPath(info.MenuPath, info.OperationId, operationMenu);
                item.Click += OperationMenu_Click;
            }

            emptyFilterBlock = new EmptyBlock(operationMenu);

            GenerateBlockz();
        }

        private void AddInputBlock(IOperation operation)
        {
            OperationBlock block = new OperationBlock();
            block.MainWindow = MainWindow;
            block.Init(operation);

            blockTable.Controls.Add(block, 0, 0);
        }

        private void AddFilterBlock(IOperation operation, int row)
        {
            OperationBlock block = new OperationBlock();
            block.MainWindow = MainWindow;
            block.Init(operation);

            blockTable.Controls.Add(block, 1, row);
            blockTable.Controls.Add(emptyFilterBlock, 1, row + 1);

            block.BlockUp += BlockUpClick;
            block.BlockDown += BlockDownClick;
            block.BlockDelete += BlockDeleteClick;
        }

        private void AddOutputBlock(IOperation operation, int row)
        {
            OperationBlock block = new OperationBlock();
            block.MainWindow = MainWindow;
            block.Init(operation);

            blockTable.Controls.Add(block, 2, row);

            block.BlockUp += BlockUpClick;
            block.BlockDown += BlockDownClick;
            block.BlockDelete += BlockDeleteClick;
        }

        private void BlockUpClick(object sender, EventArgs e)
        {
            OperationBlock block = (OperationBlock)sender;
            IOperation operation = block.Operation;

            model.MoveUpBlock(operation);

            GenerateBlockz();
        }

        private void BlockDownClick(object sender, EventArgs e)
        {
            OperationBlock block = (OperationBlock)sender;
            IOperation operation = block.Operation;

            model.MoveDownBlock(operation);

            GenerateBlockz();
        }

        private void BlockDeleteClick(object sender, EventArgs e)
        {
            OperationBlock block = (OperationBlock)sender;

            model.DeleteBlock(block.Operation);

            GenerateBlockz();
        }

        private void GenerateBlockz()
        {
            blockTable.SuspendLayout();
            blockTable.Controls.Clear();
            blockTable.RowCount = 1;

            if (model.Sequence.Counter() < 1)
            {
                blockTable.Controls.Add(new EmptyBlock(inputMenu), 0, 0);
                blockTable.ResumeLayout();
                return;
            }

            if (model.InputOperation != null)
            {
                AddInputBlock(model.InputOperation);

                if (model.PairsCount == 0)
                {
                    blockTable.Controls.Add(emptyFilterBlock, 1, 0);
                }
            }

            int row = 0;

            for (int i = 0; i < model.PairsCount; i++ )
            {
                blockTable.RowCount++;
                AddFilterBlock(model.GetFilterOperation(i) , row);

                if (model.GetOutputOperation(i) != null)
                {
                    AddOutputBlock(model.GetOutputOperation(i), row);
                }
                else
                {
                    EmptyBlock emptyBlock = new EmptyBlock(outputMenu);
                    emptyBlock.MouseClick += outputBlock_MouseClick;

                    blockTable.Controls.Add(emptyBlock, 2, row);
                }

                row++;
            }

            blockTable.ResumeLayout();
        }

       
        private void fromFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog open = new OpenFileDialog();

            open.CheckFileExists = true;
            if (open.ShowDialog() == DialogResult.OK)
            {
                OpenFile openFile = new OpenFile(open.FileName);

                model.InputOperation = openFile;

                GenerateBlockz();
            }

        }

        private void OperationMenu_Click(object sender, EventArgs e)
        {
            OperationMenuItem item = (OperationMenuItem)sender;
            
            IOperation operation = OperationFactory.GetDefaultFactory().CreateOperation(item.OperationName);
            OperationControl control = ControlFactory.GetDefaultFactory().CreateControl(item.OperationName);

            if (control != null)
            {
                //
                // WARNING: Bmp is set to null here, so controls can't use it
                // when editing operation in sequence mode
                //
                control.SetOperation(operation);
                control.IsNew = true;
                control.Bmp = null;

                OperationDialog dialog = MainWindow.EditDialog;

                dialog.SetControl(control);
                if (dialog.ShowDialog(false) == DialogResult.OK)
                {
                    model.AddFilterOperation(operation);

                    GenerateBlockz();
                }
            }
            else
            {
                model.AddFilterOperation(operation);

                GenerateBlockz();
            }         
        }

        private void noOperationToolStripMenuItem_Click(object sender, EventArgs e)
        {
            IOperation operation = new NoOperation();

            model.AddFilterOperation(operation);

            GenerateBlockz();
        }

        public void DoText()
        {
            Bitmap bmp = null;

            foreach (IOperation oper in model.Sequence)
            {
                if (oper is FromImage)
                {
                    if (MainWindow.IsMainImageSet == false)
                    {
                        MessageBox.Show("Sequence can't be executed: Main image is not set.");
                        return;
                    }

                    ((FromImage)oper).Image = MainWindow.Image;
                }           

                MainWindow.ConsoleBox.AddRow(oper.GetFormattedName(), oper.GetInfo());
                bmp = oper.Do(bmp);

                if (oper is ToExport)
                {
                    MainWindow.AddImageToTab(bmp);
                }
                else if (oper is ToImage)
                {
                    MainWindow.Image = ((ToImage)oper).Image;
                }
            }
        }

        private void fromMainImageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FromImage fromImage = new FromImage();

            model.InputOperation = fromImage;
            
            GenerateBlockz();
        }

        private void toMainImageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ToImage toImage = new ToImage();

            model.AddOutputOperation(toImage, lastRowClicked);
            
            GenerateBlockz();
        }


        private void toFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog save = new SaveFileDialog();

            if (save.ShowDialog() == DialogResult.OK)
            {
                SaveFile saveFile = new SaveFile(save.FileName);

                // Insert OutputFilter after Operation
                model.AddOutputOperation(saveFile, lastRowClicked);

                GenerateBlockz();
            }
        }

        private void outputBlock_MouseClick(object sender, MouseEventArgs e)
        {
            TableLayoutPanelCellPosition position = blockTable.GetPositionFromControl((Control)sender);

            lastRowClicked = position.Row;
        }

        private void toExportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ToExport toExport = new ToExport();

            model.AddOutputOperation(toExport, lastRowClicked);

            GenerateBlockz();
        }

        private void verticalIntensityToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Analyse analyse = new Analyse();

            analyse.AnalyseType = "vertical";

            model.AddOutputOperation(analyse, lastRowClicked);

            GenerateBlockz();
        }

        public void ClearBlockz()
        {
            model.Clear();            
            
            GenerateBlockz();
        }

        private void horizontalIntensityStatisticToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Analyse analyse = new Analyse();

            analyse.AnalyseType = "horizontal";

            model.AddOutputOperation(analyse, lastRowClicked);

            GenerateBlockz();
        }
    }
}
