using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace SymbolTable
{
    #region enums, types, etc...
    public struct SemInfo
    {
        public string value;
        public EVarType type;
    }

    public enum ESymbolType
    {
        ST_Var = 0,
        ST_Func,
        ST_Action,
        ST_Record,
        ST_NotDefined
    }

    // int, real, etc...
    public enum EVarType
    {
        VT_Int = 0,
        VT_Real,
        VT_Char,
        VT_Bool,
        VT_String,
        VT_NotDefined
    }

    public enum DecLvl
    {
        DL_Main,
        DL_Entry,
        DL_Function,
        DL_Record,
    }
    #endregion


    #region abstract class (only type and identifier)
    public abstract class ISymbolStructure
    {
// fields
        private ESymbolType mSymbolType;
        private string mIdentifier;

// constructors
        public ISymbolStructure(string _ident)
        {
            mIdentifier = _ident;
            mSymbolType = ESymbolType.ST_NotDefined;
        }

        public ISymbolStructure(string _ident, ESymbolType _st)
        {
            mIdentifier = _ident;
            mSymbolType = _st;
        }

// methods
        public virtual ESymbolType SymbolType 
        { 
            get { return mSymbolType; } 
            set { mSymbolType = value; } 
        }

        public virtual string Ident 
        { 
            get { return mIdentifier; } 
        }

    }
    #endregion


    #region class defining variable
    public class CVarInfo : ISymbolStructure
    {
        private EVarType mVarType;
        private DecLvl mDeclarationLvl;
        private ISymbolStructure mOwner;
        private char valChar;
        private int valInt;
        private string valString;
        private float valReal;
        private bool valBool;
        private bool mConstFlag;
        private bool mArgFlag;



        public void SetVal(string _val, EVarType _vt)
        {
            switch(_vt)
            {
                case EVarType.VT_Bool:
                    this.BoolVal = Boolean.Parse(_val);
                    break;
                case EVarType.VT_String:
                    this.StringVal = _val;
                    break;
                case EVarType.VT_Int:
                    this.IntVal = Int32.Parse(_val);
                    break;
                case EVarType.VT_Real:
                    _val = _val.Replace(".", ",");
                    this.RealVal = (float)Double.Parse(_val);
                    break;
            }
        }

        public float RealVal
        {
            get { return valReal; }
            set { valReal = value; }
        }
        public char CharVal
        {
            get { return valChar; }
            set { valChar = value; }
        }
        public string StringVal
        {
            get { return valString; }
            set { valString = value; }
        }
        public bool BoolVal
        {
            get { return valBool; }
            set { valBool = value; }
        }
        public int IntVal
        {
            get { return valInt; }
            set { valInt = value; }
        }

        public CVarInfo(string _ident, string _vartype)
            : base(_ident, ESymbolType.ST_Var)
        {
            mOwner = null;
            mConstFlag = false;
            mArgFlag = false;
            mDeclarationLvl = DecLvl.DL_Main;      // main by default
            _vartype = _vartype.ToUpper();
            switch(_vartype)
            {
                case "INT":
                    mVarType = EVarType.VT_Int;
                    break;
                case "BOOL":
                    mVarType = EVarType.VT_Bool;
                    break;
                case "STRING":
                    mVarType = EVarType.VT_String;
                    break;
                case "REAL":
                    mVarType = EVarType.VT_Real;
                    break;
                case "CHAR":
                    mVarType = EVarType.VT_Char;
                    break;
                default: mVarType = EVarType.VT_NotDefined;
                    break;
            }
        }

        public EVarType VarType
        {
            get { return mVarType; }
        }

        public bool IsConst
        {
            get { return mConstFlag; }
            set { mConstFlag = value; }
        }

        public bool IsParam 
        {
            get { return mArgFlag; }
            set { mArgFlag = value; }
        }

        // poziom zagnieżdżenia
        public DecLvl DeclarationLvl
        {
            get { return mDeclarationLvl; }
            set
            {
                mDeclarationLvl = value; }
        }

        // reference to owner (null if <Main>)
        public ISymbolStructure Owner
        {
            get { return mOwner; }
            set { mOwner = value; }
        }
    }
#endregion


    #region class defining record
    public class CRecordInfo : ISymbolStructure
    {
        private DecLvl mDeclarationLvl; // -1 => Database entry
        private ArrayList mVarList;
        private ISymbolStructure mOwner;    // NULL => Database entry OR Main
        private int mVarCount;

        public CRecordInfo(string _ident, ISymbolStructure _owner) : base(_ident, ESymbolType.ST_Record)
        {
            mDeclarationLvl = DecLvl.DL_Entry;   // Database entry by default
            mVarCount = 0;
            mVarList = new ArrayList();
            mOwner = _owner;
        }

        public ArrayList VarList
        {
            get { return mVarList; }
        }
        
        public DecLvl DeclarationLvl
        {
            get { return mDeclarationLvl; }
            set { mDeclarationLvl = value; }
        }
        
        public ISymbolStructure Owner 
        { 
            get { return mOwner; }
        }

        public void AddVar(CVarInfo _var)
        {
            _var.Owner = this;
            _var.DeclarationLvl = DecLvl.DL_Record;
            mVarList.Add(_var);
            mVarCount++;
        }

        public CVarInfo GetVar(string _ident)
        {
            foreach(CVarInfo var in mVarList)
            {
                if (_ident == var.Ident)
                    return var;
            }
            return null;
        }

        public int VarCount 
        {
            get { return mVarCount; }
        }

    }
#endregion


    #region class defining function or action
    public class CFuncInfo : ISymbolStructure
    {
        private int mVarCount;      // defined function vars
        private ArrayList mLocals;

        private EVarType mRetType;

        private int mArgsCount;
        private ArrayList mArgs;    // function arguments

        public CFuncInfo(string _ident, string _retType)
            : base(_ident)
        {
            mVarCount = 0;
            mArgsCount = 0;
            mArgs = new ArrayList();
            mLocals = new ArrayList();

            _retType = _retType.ToUpper();
            switch (_retType)
            {
                case "INT":
                    mRetType = EVarType.VT_Int;
                    break;
                case "BOOL":
                    mRetType = EVarType.VT_Bool;
                    break;
                case "STRING":
                    mRetType = EVarType.VT_String;
                    break;
                case "REAL":
                    mRetType = EVarType.VT_Real;
                    break;
                case "CHAR":
                    mRetType = EVarType.VT_Char;
                    break;
                default: mRetType = EVarType.VT_NotDefined;
                    break;
            }
        }

        public int GetVarCount
        {
            get { return mVarCount; }
        }

        public int GetArgCount
        {
            get { return mArgsCount; }
        }

        public EVarType RetType
        {
            get { return mRetType; }
        }

        public ArrayList Vars
        {
            get { return mLocals; }
        }

        public ArrayList Arguments
        {
            get { return mArgs; }
        }

        public void AddVar(CVarInfo _var)
        {
            _var.Owner = this;
            mVarCount++;
            mLocals.Add(_var);
        }

        public void AddArg(CVarInfo _var)
        {
            _var.Owner = this;
            _var.IsParam = true;
            mArgsCount++;
        }
    }
    #endregion
}