using System;
using System.Collections.Generic;
using System.Drawing;
using OrComp = Orienteering.Competition;
using Gtk;

namespace Orienteering.GUI {
    public class Competition {
        internal OrComp.Competition data;
        private Stage drawStage;

        public Competition(OrComp.Competition _data) {
            data = _data;
        }

        public string Name {
            get { return data.Name; }
            set { data.Name = value; }
        }

        public Stage DrawStage {
            get { return drawStage; }
            set { drawStage = value; }
        }

        public void Save(string path, DataBase dataBase) {
            data.Save(path, dataBase.data);
        }

        public Stage Stage(int number, DataBase dataBase) {
            return new Stage(data.Stage(number, dataBase.data));
        }

        public static Competition Open(string path, DataBase dataBase) {
            return new Competition(OrComp.Competition.Open(path, dataBase.data));
        }

        private DataBase db;
        private RunnersTreeView tree;
        private TreeStore RunnersTreeStore;
        public VBox Runners(DataBase dataBase) {
            db = dataBase;

            RunnersTreeStore = new TreeStore(typeof(object));
            foreach (OrComp.Club club in data.Clubs(dataBase.data)) {
                TreeIter iter = RunnersTreeStore.AppendValues(club);
                List<OrComp.Runner> runners = club.Runners(dataBase.data);
                foreach (OrComp.Runner runner in runners)
                    RunnersTreeStore.AppendValues(iter, runner);
            }

            tree = new RunnersTreeView(RunnersTreeStore, this);
            tree.EnableGridLines = TreeViewGridLines.Both;
            tree.AppendColumn(
                    Standard.treeColText("Klub/Bežec", new TreeCellDataFunc(RenderName), EditName) );

            Viewport viePo = new Viewport();
            tree.RulesHint = true;
            viePo.Add(tree);
            ScrolledWindow viewer = new ScrolledWindow();
            viewer.Add(viePo);

            VBox vbox1 = new VBox();
            Button button1 = new Button("Pridať klub");
            button1.Clicked += AddClub;
            vbox1.PackStart(button1, false, false, 2);
            vbox1.PackStart(viewer, true, true, 2);

            return vbox1;
        }

        private void AddClub(object o, EventArgs args) {
            RunnersTreeStore.AppendValues(new OrComp.Club(data));
        }

        private void RenderName(TreeViewColumn column, CellRenderer cell,
                TreeModel model, TreeIter iter) {
            int depth = RunnersTreeStore.IterDepth(iter);
            switch (depth) {
                case 0: (cell as CellRendererText).Text = (model.GetValue(iter, 0) as OrComp.Club).Name;
                        break;
                case 1: (cell as CellRendererText).Text = (model.GetValue(iter, 0) as OrComp.Runner).Name;
                        break;
            }
        }
        private void EditName(object o, EditedArgs args) {
            TreeIter iter;
            RunnersTreeStore.GetIter(out iter, new TreePath (args.Path));
            int depth = RunnersTreeStore.IterDepth(iter);
            switch (depth) {
                case 0:
                    (RunnersTreeStore.GetValue(iter, 0) as OrComp.Club).Name = args.NewText;
                    (RunnersTreeStore.GetValue(iter, 0) as OrComp.Club).Save(db.data);
                break;
                case 1: 
                    (RunnersTreeStore.GetValue(iter, 0) as OrComp.Runner).Name = args.NewText;
                    (RunnersTreeStore.GetValue(iter, 0) as OrComp.Runner).Save(db.data);
                break;
            }
        }

        private class RunnersTreeView : TreeView {
            public RunnersTreeView(TreeStore a, Competition comp) : base(a) {
                competition = comp;
            }

            private int typ;
            private static Competition competition;
            private static Dictionary<Widget, int> map;
            private OrComp.Club club;
            private OrComp.Runner runner;

            private TreeIter tmpIter;

            protected override bool OnButtonPressEvent (Gdk.EventButton evnt) {
                if (evnt.Button == 3) {
                    Gtk.TreePath path = new Gtk.TreePath();
                    this.GetPathAtPos(System.Convert.ToInt16 (evnt.X),
                            System.Convert.ToInt16 (evnt.Y), out path);
                    Gtk.TreeIter iter;

                    if (this.Model.GetIter (out iter, path)) {
                        tmpIter = iter;
                        Menu menu = new Menu();
                        MenuItem edit = new MenuItem("Upraviť");
                        edit.Activated += Edit;
                        typ = competition.RunnersTreeStore.IterDepth(iter);
                        switch (typ) {
                            case 0 :
                                club = (OrComp.Club)competition.RunnersTreeStore.GetValue (iter, 0);
                            break;
                            case 1 :
                                runner = (OrComp.Runner)competition.RunnersTreeStore.GetValue (iter, 0);
                            break;
                        }

                        menu.Append(edit);
                        if (typ == 1) {
                            MenuItem del = new MenuItem("Zmazať");
                            menu.Append(del);
                            MenuItem stages = new MenuItem("Etapy");
                            stages.Activated += StagesActivated;
                            menu.Append(stages);
                        }
                        else {
                            MenuItem addrunner = new MenuItem("Pridať pretekára");
                            addrunner.Activated += AddRunner;
                            menu.Append(addrunner);
                        }

                        menu.ShowAll();
                        menu.Popup();
                        return true;
                    }
                }
                return base.OnButtonPressEvent(evnt);
            }

            private void AddRunner(object o, EventArgs args) {
                competition.RunnersTreeStore.AppendValues(tmpIter, new OrComp.Runner(club));
            }

            private class CategoryStage {
                public OrComp.Stage Stage;
                public OrComp.Category Category;
                public bool ActiveStage;

                public CategoryStage(OrComp.Stage stage, OrComp.Category category) {
                    ActiveStage = true;
                    Stage = stage;
                    Category = category;
                }
            }

            private ListStore StageListStore;
            private TreeView tree2;
            private Dictionary<int, ListStore> categories;
            private void StagesActivated(object o, EventArgs args) {
                Dialog dialog = new Dialog("Etapy", null, Gtk.DialogFlags.DestroyWithParent);
                dialog.AddButton ("OK", ResponseType.Ok);
                dialog.AddButton ("Zavrieť", ResponseType.Close);

                List<OrComp.Stage> stages = competition.data.Stages(competition.db.data);
                StageListStore = new ListStore(typeof(CategoryStage));
                categories = new Dictionary<int, ListStore>();

                foreach (OrComp.Stage stage in stages) {
                    OrComp.Category ctg = null;
                    try {
                        ctg = runner.Result(stage, competition.db.data).Category;
                    }
                    catch {
                    }

                    StageListStore.AppendValues(new CategoryStage(stage, ctg));
                    ListStore tmp = new ListStore(typeof(string));
                    foreach (OrComp.Category category in stage.Categories(competition.db.data))
                        tmp.AppendValues(category.Name);
                    categories[stage.Number] = tmp;
                }

                tree2 = new TreeView(StageListStore);
                tree2.EnableGridLines = TreeViewGridLines.Both;
                tree2.AppendColumn(
                        Standard.treeColText("Cislo Etapy",
                            new TreeCellDataFunc(RenderStageNum), null) );
                tree2.AppendColumn(
                        Standard.treeColTogg("Etapa",
                            new TreeCellDataFunc(RenderStage), EditStage) );
                tree2.AppendColumn(
                        Standard.treeColComb("Kategoria", new ListStore(typeof(string)),
                            new TreeCellDataFunc(RenderCategory), EditCategory) );

                tree2.RulesHint = true;
                Viewport viePo = new Viewport();
                viePo.Add(tree2);
                ScrolledWindow viewer = new ScrolledWindow();
                viewer.Add(viePo);

                dialog.VBox.PackStart(viewer, true, true, 2);
                dialog.Resize(400, 600);

                dialog.ShowAll();
                if (dialog.Run() == (int)ResponseType.Ok) {
                    foreach (object[] oo in StageListStore) {
                        CategoryStage cs = (CategoryStage)oo[0];
                        if (cs.ActiveStage) {
                            try {
                                runner.Result(cs.Stage, competition.db.data).Category = cs.Category;
                            }
                            catch {
                                if (cs.Category != null)
                                    new OrComp.Result(cs.Category, runner, competition.db.data);
                            }
                        }
                        else {
//                            runner.DeleteResult(cs.Category);
                        }
                    }
                }
                dialog.Destroy();
            }

            private void RenderStageNum(TreeViewColumn column, CellRenderer cell,
                    TreeModel model, TreeIter iter) {
                CategoryStage cs = (CategoryStage)model.GetValue(iter, 0);
                (cell as CellRendererText).Text = cs.Stage.Number.ToString();
            }

            private void RenderStage(TreeViewColumn column, CellRenderer cell,
                    TreeModel model, TreeIter iter) {
                CategoryStage cs = (CategoryStage)model.GetValue(iter, 0);
                (cell as CellRendererToggle).Active = cs.ActiveStage;
            }
            private void EditStage(object o, ToggledArgs args) {
                TreeIter iter;
                StageListStore.GetIter (out iter, new TreePath (args.Path));
                CategoryStage cs = (CategoryStage)StageListStore.GetValue(iter, 0);
                cs.ActiveStage ^= true;
            }

            private void RenderCategory(TreeViewColumn column, CellRenderer cell,
                    TreeModel model, TreeIter iter) {
                CategoryStage cs = (CategoryStage)StageListStore.GetValue(iter, 0);
                (cell as CellRendererCombo).Model = categories[cs.Stage.Number];
                if (cs.Category != null)
                    (cell as CellRendererCombo).Text = cs.Category.Name;
                else
                    (cell as CellRendererCombo).Text = "";
            }
            private void EditCategory(object o, EditedArgs args) {
                TreeIter iter;
                StageListStore.GetIter (out iter, new TreePath (args.Path));
                CategoryStage cs = (CategoryStage)StageListStore.GetValue(iter, 0);
                cs.Category = cs.Stage.Category(args.NewText, competition.db.data);
            }

            private void Edit(object o, EventArgs args) {
                switch (typ) {
                    case 0:
                        EditClub(club);
                    break;
                    case 1:
                        EditRunner(runner);
                    break;
                }
            }

            private void EditRunner(OrComp.Runner runner) {
                Dialog dialog = new Dialog("Pretekár", null, Gtk.DialogFlags.DestroyWithParent);
                dialog.AddButton ("OK", ResponseType.Ok);
                dialog.AddButton ("Zavrieť", ResponseType.Close);

                map = new Dictionary<Widget, int>();

                Table table = new Table(2, 3, false);
                table.Attach(new Label("Meno"), 0, 1, 0, 1);
                table.Attach(new Label("Registračné číslo"), 1, 2, 0, 1);

                List<Widget> zoz = new List<Widget>();
                zoz.Add(new Entry(runner.Name));
                zoz.Add(new Entry(runner.RegNumber.ToString()));

                for (int i=0; i<zoz.Count; i++) {
                    if (i!=2) {
                        (zoz[i] as Entry).IsEditable = true;
                        (zoz[i] as Entry).Changed += Editing;
                    }
                    map[zoz[i]]=i;
                    table.Attach(zoz[i], (uint)i, (uint)i+1, 1, 2);
                }

                dialog.VBox.Add(table);
                dialog.ShowAll();
                if (dialog.Run() == (int)ResponseType.Ok)
                    runner.Save(competition.db.data);
                dialog.Destroy ();
            }

            private void EditClub(OrComp.Club club) {
                Dialog dialog = new Dialog("Klub", null, Gtk.DialogFlags.DestroyWithParent);
                dialog.AddButton("OK", ResponseType.Ok);
                dialog.AddButton("Zavrieť", ResponseType.Close);

                map = new Dictionary<Widget, int>();

                Table table = new Table(2, 3, false);
                table.Attach(new Label("Meno"), 0, 1, 0, 1);
                table.Attach(new Label("Skratka"), 1, 2, 0, 1);
                table.Attach(new Label("Krajina"), 2, 3, 0, 1);

                List<Widget> zoz = new List<Widget>();
                zoz.Add(new Entry(club.Name));
                zoz.Add(new Entry(club.Abbreviation));
                zoz.Add(new Entry(club.Country));

                for (int i = 0; i < zoz.Count; i++) {
                    (zoz[i] as Entry).IsEditable = true;
                    (zoz[i] as Entry).Changed += Editing;
                    if (i > 0) {
                        (zoz[i] as Entry).MaxLength = 3;
                    }

                    map[zoz[i]]=i;
                    table.Attach(zoz[i], (uint)i, (uint)i+1, 1, 2);
                }

                dialog.VBox.Add(table);
                dialog.ShowAll();
                if (dialog.Run() == (int)ResponseType.Ok)
                    runner.Save(competition.db.data);
                dialog.Destroy ();
            }

            private void Editing(object o, EventArgs args) {
                Entry entry = (Entry)o;
                switch (typ) {
                    case 0 : 
                        switch (map[entry]) {
                            case 0: club.Name = entry.Text; break;
                            case 1: club.Abbreviation = entry.Text; break;
                            case 2: club.Country = entry.Text; break;
                        }
                    break;
                    case 1 : 
                        switch (map[entry]) {
                            case 0: runner.Name = entry.Text; break;
                            case 1: try {
                                        runner.RegNumber = Standard.String2Int32(entry.Text);
                                    }
                                    catch {}
                                break;
                        }
                    break;
                }
            }
        }

    }
}
