using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Reflection;

namespace CobXmlSupport
{
    public class CobRow
    {
        private List<RowWord> __wordList;
        private string __rowSource;
        private int __startPos;
        private int __occNum;
        private string moveCode;
        private string moveFromCode;

        public CobRow(string rowSource)
        {
            //Debug.WriteLine(rowSource);
            __rowSource = rowSource;
            analyseRowSource(__rowSource);
            checkLongNames();
            this.LevelChild = null;
            this.LevelParent = null;
        }

        public CobRow(string rowSource,bool chkLongNames)
        {
            //Debug.WriteLine(rowSource);
            __rowSource = rowSource;
            analyseRowSource(__rowSource);
            if (chkLongNames)
            {
                checkLongNames();
            }
            this.LevelChild = null;
            this.LevelParent = null;
        }

        public CobRow LevelParent { get; set; }
        public CobRow LevelChild { get; set; }
        public int CobLevel { get; set; }
        public bool isAttribute { get; set; }
        public string LocalKey { get; set; }
        public string SampleStr { get; set; }

        public string Move_Code
        {
            get
            {
                return moveCode;
            }
        }

        public string MoveCode {
            get {
                return "      *" + S.strX(' ', 72 - 15 - this.FieldName.Length) + "------" + this.FieldName + "\r\n" +
                    moveCode +
                    "\r\n      *" + S.strX(' ', 72 - 15 - this.FieldName.Length) + "------" + this.FieldName + "\r\n";
            }
            set{
                moveCode = value;
            }
        }
                    //Holding code-parts used when generating moves, to structure
                    //Could be a Variable, simple or qualified, could be retreival code.
                    //Will replace "MOVE " when generating move sequences

        public string Move_FromCode
        {
            get
            {
                return moveFromCode;
            }
        }


        public string MoveFromCode {
            get {
                return "      *" + S.strX(' ', 72 - 15 - this.FieldName.Length) + "------" + this.FieldName + "\r\n" +
                    moveFromCode +
                    "\r\n      *" + S.strX(' ', 72 - 15 - this.FieldName.Length) + "------" + this.FieldName + "\r\n";
            }
            set{
                moveFromCode = value;
                // Debug för att se var datat fyll på
                //StackTrace stackTrace = new StackTrace();
                //MethodBase methBase = stackTrace.GetFrame(1).GetMethod();
                //Debug.WriteLine("MoveFromCode -> "+ methBase.Name.ToString() + " calls MoveFromCode saving " + value);
                // Debug för att se var datat fyll på
            }
        }
                    //Holding code-parts used when generating moves, from structure
                    //Could be a Variable, simple or qualified, could be retreival code.
                    //Will replace "TO " when generating move sequences

        public string FieldName
        {
            get
            {
                return __wordList[1].ToString();
            }
            set
            {
                __wordList[1] = new RowWord(value, __wordList[1].startPos, __wordList[1].isQuoted);
                checkLongNames();
            }
        }

        public string Value
        {
            get
            {
                return findCodeValue("value");
            }
        }

        public string TagName
        {
            get
            {
                return findCodeValue("identified");
            }
        }

        public string CountIn
        {
            get
            {
                return findCodeValue("count");
            }
        }
        public string FieldDef
        {
            get
            {
                return findCodeValue("pic");
            }
        }
        public string Hirarchy
        {
            get
            {
                return localHirarchy();
            }
        }

        public bool isOccurs
        {
            get
            {
                return findCodeValue("occurs").Equals("true");
            }
        }

        public int occNum
        {
            get
            {
                if (this.isOccurs)
                {
                    return __occNum;
                }
                else return 1;
            }
        }

        public static string checkLongNames(string inStr, int maxLngth=30)
        {
            string tmp = inStr;
            if (inStr.Length > maxLngth)
            {
                int shortenLength = 8;
                string tstStr = "";
                tstStr = analyseAndShortenCamelFormedName(tmp, shortenLength);
                while (shortenLength > 0 && !(tstStr.Length < maxLngth))
                {
                    //Debug.WriteLine(tmp + "<-->"+tstStr);
                    shortenLength--;
                    tstStr = analyseAndShortenCamelFormedName(tmp, shortenLength);
                }
                //Debug.WriteLine(tmp + "<-->" + tstStr);
                tmp = tstStr;
            }
            return tmp;
        }

        private void checkLongNames()
        {
            __wordList[1] = new RowWord(checkLongNames(__wordList[1].ToString()), __wordList[1].startPos, __wordList[1].isQuoted);
        }

        private static string analyseAndShortenCamelFormedName(string inPut, int maxLow)
        {
            string markStr = "";
            int lowCount = 0;
            foreach (char c in inPut)
            {
                if (Char.IsUpper(c))
                {
                    markStr += c;
                    lowCount = 0;
                }
                else
                {
                    if (lowCount < maxLow)
                    {
                        markStr += c;
                        if(!c.Equals('_')) lowCount++;
                    }
                }
            }
            return markStr;
        }

/// <summary>
/// Find a value for certain code word in the wordtable of the cobol row
/// </summary>
/// <param name="searchVal">desired value</param>
/// <returns>value as string</returns>
        private string findCodeValue(string searchVal)
        {
            RowWord[] rws = __wordList.ToArray();
            string tmp = "";
            for (int i = 0; i < __wordList.Count; i++)
            {
                switch (searchVal.ToLower()){
                    case "value":{
                        if (__wordList[i].ToString().ToLower() == searchVal.ToLower())
                        {
                            tmp = __wordList[i + 1].ToString();
                            i=__wordList.Count;
                        }
                        break;
                    }
                    case "identified":
                        {
                            if (__wordList[i].ToString().ToLower() == searchVal.ToLower())
                            {
                                tmp = __wordList[i + 1].ToString();
                                if (tmp.ToLower() == "by")
                                {
                                    tmp = __wordList[i + 2].ToString();
                                }
                                i = __wordList.Count;
                            }
                            break;
                        }
                    case "count":
                        {
                            if (__wordList[i].ToString().ToLower() == searchVal.ToLower())
                            {
                                tmp = __wordList[i + 1].ToString();
                                if (tmp.ToLower() == "in")
                                {
                                    tmp = __wordList[i + 2].ToString();
                                }
                                if (tmp.Contains('.'))
                                {
                                    tmp = tmp.Substring(0, tmp.IndexOf('.'));
                                }
                                i = __wordList.Count;
                            }
                            break;
                        }
                    case "pic":
                        {
                            if (__wordList[i].ToString().ToLower() == searchVal.ToLower())
                            {
                                tmp = __wordList[i].ToString() +" "+__wordList[i + 1].ToString();
                                i = __wordList.Count;
                            }
                            break;
                        }
                    case "occurs":
                        {
                            tmp = "false";
                            if (__wordList[i].ToString().ToLower() == searchVal.ToLower())
                            {
                                tmp = "true";
                                if (__wordList[i + 1].NumVal().Length > 0)
                                {
                                    __occNum = int.Parse(__wordList[i + 1].NumVal());
                                }

                                i = __wordList.Count;
                            }
                            break;
                        }
		            default: {
                        break;
	                }
                }
            }
            return tmp;
        }

        public string wrapped(int maxPos=72)
        {
            RowWord[] rowWords = __wordList.ToArray();
            string tmpString = "",extrString="";
            int actPos=0;
            tmpString += "".PadLeft(__startPos);
            actPos=__startPos;
            for (int i = 0; i < rowWords.Length; i++)
            {
                rowWords[i].startPos=actPos;
                if (rowWords[i].endPos < maxPos)
                {
                    tmpString += rowWords[i].ToString() + " ";
                    actPos = rowWords[i].endPos + 2;
                }
                else
                {
                    if (rowWords[i].isQuoted)
                    {
                        // a quoted string fills the row to maxPos and the remaining on next row with "-" in pos 7
                        if (actPos >= maxPos)
                        {
                            tmpString += "\r\n" + "".PadLeft(__startPos);
                            actPos = __startPos+1;
                            i--;
                        }
                        else
                        {
                            extrString = rowWords[i].ToString();
                            tmpString += extrString.Substring(0, maxPos - rowWords[i].startPos); // +"\"";
                            tmpString += "\r\n" + "      -" + "".PadLeft(__startPos - 7) + "\"";
                            actPos = __startPos+2;
                            RowWord tmpRW = new RowWord(extrString.Substring(maxPos - rowWords[i].startPos), actPos, true);
                            if (tmpRW.endPos >= maxPos)
                            {
                                extrString = tmpRW.ToString();
                                tmpString += extrString.Substring(0, maxPos - tmpRW.startPos); // +"\"";
                                tmpString += "\r\n" + "      -" + "".PadLeft(__startPos - 7) + "\"";
                                actPos = __startPos+2;
                                tmpRW = new RowWord(extrString.Substring(maxPos - tmpRW.startPos), actPos, true);
                            }
                            tmpString += tmpRW.ToString()+" ";
                            actPos = tmpRW.endPos + 2;
                        }
                    }
                    else
                    {
                        if (rowWords[i].isComment)
                        {
                            rowWords[i].startPos = actPos;
                            tmpString += rowWords[i].ToString();
                        }
                        else
                        {
                            tmpString += "\r\n" + "".PadLeft(__startPos);
                            actPos = __startPos + 1;
                            rowWords[i].startPos = actPos;
                            tmpString += rowWords[i].ToString() + " ";
                            actPos = rowWords[i].endPos + 2;
                        }
                    }
                }
            }
            return tmpString;
        }


        private void analyseRowSource(string row_Source)
        {
            string sChar, tmpStr="";
            int wrdStart=0;
            bool filling=false, comment=false;
            __wordList = new List<RowWord>();
            for(int i=0;i<row_Source.Length;i++){
                sChar = row_Source.Substring(i, 1);
                switch (sChar)
                {
                    case " ":
                        {
                            if (filling||comment)
                            {
                                tmpStr += sChar;
                            }
                            else
                            {
                                if (tmpStr.Length > 0)
                                {
                                    __wordList.Add(new RowWord(tmpStr, wrdStart, false));
                                    tmpStr = "";
                                    wrdStart = 0;
                                }
                            }
                            break;
                        }
                    case "\"":
                        {
                            if (comment)
                            {
                                tmpStr += sChar;
                            }
                            else
                            {
                                filling = !filling;
                                if (filling)
                                {
                                    wrdStart = i;
                                    tmpStr += sChar;
                                }
                                else
                                {
                                    tmpStr += sChar;
                                    __wordList.Add(new RowWord(tmpStr, wrdStart, true));
                                    tmpStr = "";
                                    wrdStart = 0;
                                }
                            }
                            break;
                        }
                    case "*":
                        {
                            if (i == 6 || (i < row_Source.Length - 1 && row_Source.Substring(i + 1, 1) == ">"))
                            {
                                comment = true;
                                wrdStart = i;
                            }
                            tmpStr += sChar;
                            break;
                        }
                    default:
                        {
                            if (filling||comment)
                            {}
                            else
                            {
                                if (tmpStr.Length == 0)
                                {
                                    wrdStart = i;
                                }
                            }
                            tmpStr += sChar;
                            break;
                        }
                }
            }
            if (tmpStr.Length > 0)
            {
                if (tmpStr.Length > 1 && tmpStr.Substring(tmpStr.Length - 1, 1) == ".")
                {
                    __wordList.Add(new RowWord(tmpStr.Substring(0, tmpStr.Length - 1), wrdStart, false));

                    __wordList.Add(new RowWord(".", wrdStart + tmpStr.Length, false));
                    tmpStr = "";
                    wrdStart = 0;
                }
                else
                {
                    __wordList.Add(new RowWord(tmpStr, wrdStart, false));
                    tmpStr = "";
                    wrdStart = 0;
                }
            }
            if (__wordList.Count > 0)
            {
                RowWord e = __wordList.First();
                __startPos = e.startPos;
            }
            else __startPos = 0;
        }

        private string localHirarchy()
        {
            string tmp="";
            List<string> tagNames = new List<string>();
            CobRow tmpRow = this;
            while (tmpRow.LevelParent != null)
            {
                tagNames.Add(tmpRow.TagName);
                tmpRow = tmpRow.LevelParent;
            }
            tagNames.Add(tmpRow.TagName);
            tagNames.Reverse();
            foreach (string ts in tagNames)
            {
                tmp += ts.Replace("\"", "") + "/";
            }
            return tmp;
        }

        public override string ToString()
        {
            // Just for debug reasons
            string outString = base.ToString() + Environment.NewLine;
            //return base.ToString();
            foreach (RowWord xx in __wordList)
            {
                outString += " " + xx.ToString();
            }
            outString += Environment.NewLine;
            outString += " " + __rowSource + Environment.NewLine + Environment.NewLine;
            return outString;
        }

    }
}
