using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;

namespace PinyinModel
{
    internal class Lexicon
    {
        private class Node
        {
            public Dictionary<string, Node> children;
            public List<string> phrases;
            public Node()
            {
                children = new Dictionary<string, Node>();
                phrases = new List<string>();
            }
        }

        private Node root = new Node();
        private int max_length = 0;
        PinyinSyllable syllables;
        HashSet<string> lexicon = new HashSet<string>();

        internal int MaxLength
        {
            get { return max_length; }
        }
        internal int Count
        {
            get { return lexicon.Count; }
        }

        internal Lexicon(string filename, PinyinSyllable syllables)
        {
            using (StreamReader reader = File.OpenText(filename))
            {
                Console.Write("Loading dictionary from {0} ... ", filename);
                this.syllables = syllables;
                string line = null;
                while ((line = reader.ReadLine()) != null)
                {
                    ParseLine(line);
                }
                Console.WriteLine("Done.");
            }
        }

        public List<string> GetPhrases(string[] pinyin_sequence)
        {
            return GetPhrasesAbstract(root, pinyin_sequence, 0);
        }

        private void ParseLine(string line)
        {
            int sep_pos = line.IndexOf('\t');
            string phrase = line.Substring(sep_pos + 1);
            string[] section = line.Substring(0,sep_pos).Split('\'');
            InsertPhrase(root, phrase, section, 0);
        }

        private void InsertPhrase(Node current, string phrase, string[] pinyin_section, int index)
        {
            string pinyin = pinyin_section[index];

            if (!this.syllables.IsValidSyllable(pinyin))
                return;

            Node child;
            if (!current.children.ContainsKey(pinyin))
            {
                child = current.children[pinyin] = new Node();
            }
            else
            {
                child = current.children[pinyin];
            }

            if (index == pinyin_section.Length - 1)
            {
                child.phrases.Add(phrase);
                lexicon.Add(phrase);
                if (phrase.Length > max_length)
                    max_length = phrase.Length;
            }
            else
            {
                InsertPhrase(child, phrase, pinyin_section, index + 1);
            }
        }

        private List<string> GetPhrasesAbstract(Node current, string[] pinyin_section, int index)
        {
            string pinyin = pinyin_section[index];
            if (!current.children.ContainsKey(pinyin))
                return null;

            Node child = current.children[pinyin];
            if (index == pinyin_section.Length - 1)
            {
                return child.phrases;
            }
            else
            {
                return GetPhrasesAbstract(child, pinyin_section, index + 1);
            }
        }

        internal bool Contains(string phrase)
        {
            return lexicon.Contains(phrase);
        }
    }
}
