using System;
using System.Collections.Generic;
using Orienteering.Standard;

namespace Orienteering.Data {
    public class Stage {
        private int number;
        private DateTime startTime;
        private string organizer, mapPath;
        private Orienteering.Data.Competition competition;

        public Stage() {
        }

        public Stage(int _number, string _organizer, Competition _comp) {
            number = _number;
            organizer = _organizer;
            competition = _comp;
        }

        public DateTime StartTime {
            get { return startTime; }
            set { startTime = value; }
        }
        
        public string MapPath {
            get { return mapPath; }
            set { mapPath = value; }
        }

        public string Organizer {
            get { return organizer; }
            set { organizer = value; }
        }

        public int Number {
            get { return number; }
            set { number = value; }
        }

        public Competition Competition {
            get { return competition; }
            set { competition = value; }
        }

        public void AddCourse(Course course, DataBase dataBase) {
            if (dataBase.db.Query<Course>(delegate(Course cour) {
                   return cour.Stage == this && course.Name == cour.Name;
               }).Count == 0) {
                dataBase.db.Set(course);
            }
            else throw new AlreadyExists();
        }

        public void AddObject(Object obj, DataBase dataBase) {
            if (dataBase.db.Query<Object>(delegate(Object o) {
                return o.Stage == this && obj.Number == o.Number &&
                    o.GetType() == obj.GetType();
               }).Count == 0) {
                dataBase.db.Set(obj);
            }
            else {
                Console.WriteLine(obj.GetType()+" "+obj.Number+" "+this.Number);
                throw new AlreadyExists();
            }
        }

        public List<Object> Objects(DataBase dataBase) {
            return new List<Object>(
                dataBase.db.Query<Object>(
                    delegate(Object obj) {
                        return obj.Stage == this;
                    }
                )
            );
        }

        public List<Course> Courses(DataBase dataBase) {
            return new List<Course>(
                dataBase.db.Query<Course>(
                    delegate(Course course) {
                        return course.Stage == this;
                    }
                )
            );
        }

        public List<Category> Categories(DataBase dataBase) {
            return new List<Category>(
                dataBase.db.Query<Category>(
                    delegate(Category category) {
                        return category.Course.Stage == this;
                    }
                )
            );
        }

        public Result Result(string name, DataBase dataBase) {
            IList<Result> res = dataBase.db.Query<Result>(
                    delegate(Result result) {
                        return result.Runner.Name == name && result.Category.Course.Stage == this;
                    }
                );
            if (res.Count == 0)
                throw new DoesntExist();
            else return res[0];
        }

        public Category Category(string name, DataBase dataBase) {
            IList<Category> res = dataBase.db.Query<Category>(
                    delegate(Category category) {
                        return category.Name == name && category.Course.Stage == this;
                    }
                );
            if (res.Count == 0)
                throw new DoesntExist();
            else return res[0];
        }

        public Course Course(string name, DataBase dataBase) {
            IList<Course> res = dataBase.db.Query<Course>(
                    delegate(Course course) {
                        return course.Name == name && course.Stage == this;
                    }
                );
            if (res.Count == 0)
                throw new DoesntExist();
            else return res[0];
        }

        public Start Start(int num, DataBase dataBase) {
            IList<Start> res = dataBase.db.Query<Start>(
                    delegate(Start start) {
                        return start.Number == num && start.Stage == this;
                    }
                );
            if (res.Count == 0)
                throw new DoesntExist();
            else return res[0];
        }

        public Control Control(int num, DataBase dataBase) {
            IList<Control> res = dataBase.db.Query<Control>(
                    delegate(Control control) {
                        return control.Number == num && control.Stage == this;
                    }
                );
            if (res.Count == 0)
                throw new DoesntExist();
            else return res[0];
        }

        public Finish Finish(int num, DataBase dataBase) {
            IList<Finish> res = dataBase.db.Query<Finish>(
                    delegate(Finish finish) {
                        return finish.Number == num && finish.Stage == this;
                    }
                );
            if (res.Count == 0)
                throw new DoesntExist();
            else return res[0];
        }

        public List<Start> Starts(DataBase dataBase) {
            return new List<Start>(
                dataBase.db.Query<Start>(
                    delegate(Start start) {
                        return start.Stage == this;
                    }
                )
            );
        }

        public List<Finish> Finishes(DataBase dataBase) {
            return new List<Finish>(
                dataBase.db.Query<Finish>(
                    delegate(Finish finish) {
                        return finish.Stage == this;
                    }
                )
            );
        }

        public List<Control> Controls(DataBase dataBase) {
            return new List<Control>(
                dataBase.db.Query<Control>(
                    delegate(Control control) {
                        return control.Stage == this;
                    }
                )
            );
        }

        public void Save(DataBase dataBase) {
            dataBase.db.Set(this);
        }
    }
}
