//  MeCab -- Yet Another Part-of-Speech and Morphological Analyzer
//
//  Copyright(C) 2001-2006 Taku Kudo <taku@chasen.org>
//  Copyright(C) 2004-2006 Nippon Telegraph and Telephone Corporation
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace NMeCab.Core
{
    public class CharProperty
    {
        #region Const

        private const string CharPropertyFile = "char.bin";

        #endregion

        #region Field/Property

        private string[] cList;

        private CharInfo[] charInfoList;

        public int Size
        {
            get { return this.cList.Length; }
        }

        #endregion

        #region Open

        public void Open(string dicDir)
        {
            string fileName = Path.Combine(dicDir, CharProperty.CharPropertyFile);

            using (FileStream stream = new FileStream(fileName, FileMode.Open))
            using (BinaryReader reader = new BinaryReader(stream))
            {
                this.Open(reader, fileName);
            }
        }

        public void Open(BinaryReader reader, string fileName = "")
        {
            uint cSize = reader.ReadUInt32();

            if (reader.BaseStream.CanSeek)
            {
                uint fSize = sizeof(uint) + (32u * cSize) + (sizeof(uint) * ushort.MaxValue); // ushort.MaxValue=0xFFFF
                if (reader.BaseStream.Length != fSize)
                    throw new MeCabInvalidFileException("invalid file size", fileName);
            }

            this.cList = new string[cSize];
            for (int i = 0; i < cSize; i++)
            {
                byte[] asciiBytes = reader.ReadBytes(32);
                this.cList[i] = Encoding.ASCII.GetString(asciiBytes).TrimEnd('\0');
            }

            this.charInfoList = new CharInfo[0xFFFF];
            for (int i = 0; i < this.charInfoList.Length; i++)
            {
                this.charInfoList[i] = new CharInfo(reader);
            }
        }

        #endregion

        #region Get Infometion

        public string Name(int i)
        {
            return this.cList[i];
        }

        public unsafe char* SeekToOtherType(char* begin, char* end, CharInfo c, CharInfo* fail, int* cLen)
        {
            char* p = begin;
            *cLen = 0;

            *fail = this.GetCharInfo(*p);

            while (p != end && c.IsKindOf(*fail))
            {
                p++;
                (*cLen)++;
                c = *fail;

                *fail = this.GetCharInfo(*p);
            }

            return p;
        }

        public unsafe CharInfo GetCharInfo(char c)
        {
            return this.charInfoList[c];
        }

        #endregion
    }
}
