// 
// Copyright (c) 2013-2016 Carsten Sonne Larsen <cs@innolan.dk>
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;
using Ntp.Analyzer.Config.Node.Navigation;
using Ntp.Analyzer.Config.Syntax.Option;
using Ntp.Analyzer.Config.Syntax.Setting;
using Ntp.Analyzer.Config.Table;

namespace Ntp.Analyzer.Config.Syntax
{
    public class MenuItemSyntaxNode : SyntaxNode<MenuItemConfiguration>
    {
        public MenuItemSyntaxNode(string name, int line)
            : base(Symbol.KeywordItem, name, line)
        {
            type = MenuItemType.Unknown;
        }

        private ISyntaxNode linkable;

        private Uri location;
        private MenuItemType type;

        protected override MenuItemConfiguration InternalCompile()
        {
            var caption = Nodes.SingleOrDefault(n => n.Symbol == Symbol.KeywordCaption) as StringSettingNode;
            var dropdown = Nodes.SingleOrDefault(n => n.Symbol == Symbol.KeywordDropdown) as StringSettingNode;
            var submenu = Nodes.SingleOrDefault(n => n.Symbol == Symbol.KeywordMenu) as MenuSyntaxNode;

            // NOTICE: Consider another method to archive the same result
            ILinkable compiledLinkable = null;
            if (linkable != null)
            {
                linkable.CompileNode();
                compiledLinkable = linkable.CompiledNode as ILinkable;
            }

            switch (type)
            {
                case MenuItemType.Spacer:
                    return new SpacerMenuItemConfiguration(Name);
                case MenuItemType.Header:
                    return new HeaderMenuItemConfiguration(Name, caption?.Value);
                case MenuItemType.Name:
                    return new HeadMenuItemConfiguration(Name, caption?.Value, location);
                case MenuItemType.Link:
                    return new LinkMenuItemConfiguration(Name, caption?.Value, location);
                case MenuItemType.Page:
                    return new PageMenuItemConfiguration(Name, caption?.Value, compiledLinkable);
                case MenuItemType.Dropdown:
                    return new DropdownItemConfiguration(Name, dropdown?.Value, submenu?.Compile());
                case MenuItemType.Unknown:
                    return null;
                default:
                    return null;
            }
        }

        protected override void InternalResolve(SymbolTable table)
        {
            if (type == MenuItemType.Unknown)
            {
                var typeNode = Nodes.SingleOrDefault(n => n.Symbol == Symbol.KeywordType) as MenuItemTypeNode;
                if (typeNode != null)
                    type = typeNode.ItemType;
            }

            if (type == MenuItemType.Page)
            {
                var pageName = Nodes.SingleOrDefault(n => n.Symbol == Symbol.KeywordPage) as StringSettingNode;
                if (pageName == null)
                    return;

                linkable = table.Lookup(pageName.Value);
            }
        }

        protected override void ValidateMandatories()
        {
            CheckIsUnique(new List<Symbol>
            {
                Symbol.KeywordPage,
                Symbol.KeywordCaption,
                Symbol.KeywordLink,
                Symbol.KeywordDropdown,
                Symbol.KeywordType,
                Symbol.KeywordContent
            });

            if (Nodes.Count(n => n.Symbol == Symbol.KeywordDropdown) > 0)
            {
                type = MenuItemType.Dropdown;
            }
            else if (Nodes.Count(n => n.Symbol == Symbol.KeywordPage) > 0)
            {
                type = MenuItemType.Page;
            }
            else if (Nodes.Count(n => n.Symbol == Symbol.KeywordLink) > 0)
            {
                type = MenuItemType.Link;
            }
            else
            {
                CheckAllIsPresent(new List<Symbol> {Symbol.KeywordType});
            }
        }

        protected override void ValidateReferences(SymbolTable table)
        {
            var pageName = Nodes.SingleOrDefault(n => n.Symbol == Symbol.KeywordPage) as StringSettingNode;
            if (pageName != null)
            {
                string keyword = Keyword.Find(Symbol.KeywordItem).Name;
                var reference = table.Lookup(pageName.Value);
                if (reference == null)
                {
                    AddReferenceNameError(pageName, keyword, pageName.Value);
                }
            }

            var link = Nodes.SingleOrDefault(n => n.Symbol == Symbol.KeywordLink) as StringSettingNode;
            if (link == null)
                return;

            var linkKeyword = Keyword.Find(Symbol.KeywordLink).Name;
            location = CheckLink(link.Value, linkKeyword);
        }

        protected override void ValidateTypes()
        {
            CheckTypeIs<StringSettingNode>(Symbol.KeywordPage);
            CheckTypeIs<StringSettingNode>(Symbol.KeywordCaption);
            CheckTypeIs<StringSettingNode>(Symbol.KeywordLink);
            CheckTypeIs<StringSettingNode>(Symbol.KeywordDropdown);
            CheckTypeIs<MenuItemTypeNode>(Symbol.KeywordType);
        }
    }
}