using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using U.ListOperations;
using U.StringOperations.Classes.ClassHelpers;

namespace U.StringOperations
{
    public class StrFunc
    {
        private const Str.ParenthesisTypes PAR = Str.ParenthesisTypes.Regular;
        private const Str.Delimiter DEL = Str.Delimiter.Comma;


        private Str.ParenthesisTypes parenthesisType;
        private Str.Delimiter delimiter;
        private string funcString;
        private string funcName;
        private List<string> argsList;
        


        // CONSTRUCTORS - 1
        public StrFunc(string funcString) { constructor1(funcString, PAR, DEL); }
        public StrFunc(string funcString, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter) { constructor1(funcString, parenthesisType, delimiter); }
        // CONSTRUCTORS - 2
        public StrFunc(string funcName, List<string> argsList) { constructor2(funcName, argsList, PAR, DEL); }
        public StrFunc(string funcName, List<bool> argsList) { constructor2(funcName, Str.toString(argsList), PAR, DEL); }
        public StrFunc(string funcName, List<int> argsList) { constructor2(funcName, Str.toString(argsList), PAR, DEL); }
        public StrFunc(string funcName, List<double> argsList) { constructor2(funcName, Str.toString(argsList), PAR, DEL); }
        public StrFunc(string funcName, List<string> argsList, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter) { constructor2(funcName, argsList, parenthesisType, delimiter); }
        public StrFunc(string funcName, List<bool> argsList, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter) { constructor2(funcName, Str.toString(argsList), parenthesisType, delimiter); }
        public StrFunc(string funcName, List<int> argsList, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter) { constructor2(funcName, Str.toString(argsList), parenthesisType, delimiter); }
        public StrFunc(string funcName, List<double> argsList, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter) { constructor2(funcName, Str.toString(argsList), parenthesisType, delimiter); }

        
        // GETTERS
        public string getFuncString() { return this.funcString; }
        public string getFuncName() { return this.funcName; }
        public int getNbArgs() { return this.argsList.Count; }
        public List<string> getArgs() { return this.argsList; }
        public List<int> getArgsInt() { return Str.toInt(this.argsList); }
        public List<double> getArgsDouble() { return Str.toDouble(this.argsList); }
        public string getArg(int index) { return this.argsList[index]; }
        public int getArgInt(int index) { return Str.toInt(this.argsList[index]); }
        public double getArgDouble(int index) { return Str.toDouble(this.argsList[index]); }


        // STATIC - Standard
        public static string getFuncString(string funcName, List<string> argsList)
        {
            return new StrFunc(funcName, argsList).getFuncString();
        }
        public static string getFuncString(string funcName, List<bool> argsList)
        {
            return new StrFunc(funcName, argsList).getFuncString();
        }
        public static string getFuncString(string funcName, List<int> argsList)
        {
            return new StrFunc(funcName, argsList).getFuncString();
        }
        public static string getFuncString(string funcName, List<double> argsList)
        {
            return new StrFunc(funcName, argsList).getFuncString();
        }
        public static string getFuncName(string funcString)
        {
            return new StrFunc(funcString).getFuncName();
        }
        public static int getNbArgs(string funcString)
        {
            return new StrFunc(funcString).getNbArgs();
        }
        public static List<string> getArgs(string funcString)
        {
            return new StrFunc(funcString).getArgs();
        }
        public static List<int> getArgsInt(string funcString)
        {
            return new StrFunc(funcString).getArgsInt();
        }
        public static List<double> getArgsDouble(string funcString)
        {
            return new StrFunc(funcString).getArgsDouble();
        }

        // STATIC
        public static string getFuncName(string funcString, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter)
        {
            return new StrFunc(funcString, parenthesisType, delimiter).getFuncName();
        }
        public static int getNbArgs(string funcString, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter)
        {
            return new StrFunc(funcString, parenthesisType, delimiter).getNbArgs();
        }
        public static List<string> getArgs(string funcString, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter)
        {
            return new StrFunc(funcString, parenthesisType, delimiter).getArgs();
        }
        public static List<int> getArgsInt(string funcString, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter)
        {
            return new StrFunc(funcString, parenthesisType, delimiter).getArgsInt();
        }
        public static List<double> getArgsDouble(string funcString, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter)
        {
            return new StrFunc(funcString, parenthesisType, delimiter).getArgsDouble();
        }
        // getFuncString
        public static string getFuncString(string funcName, List<string> argsList, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter)
        {
            return new StrFunc(funcName, argsList, parenthesisType, delimiter).getFuncString();
        }
        public static string getFuncString(string funcName, List<bool> argsList, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter)
        {
            return new StrFunc(funcName, argsList, parenthesisType, delimiter).getFuncString();
        }
        public static string getFuncString(string funcName, List<int> argsList, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter)
        {
            return new StrFunc(funcName, argsList, parenthesisType, delimiter).getFuncString();
        }
        public static string getFuncString(string funcName, List<double> argsList, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter)
        {
            return new StrFunc(funcName, argsList, parenthesisType, delimiter).getFuncString();
        }
        // getFuncString with subset of args
        public static string getFuncSubString(string funcString, List<int> includedArgIndices, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter)
        {
            StrFunc sf = new StrFunc(funcString, parenthesisType, delimiter);
            List<string> subArgs = UList.getSubset(sf.getArgs(), includedArgIndices);
            return getFuncString(sf.getFuncName(), subArgs, parenthesisType, delimiter);
        }
        public static string getFuncSubString(string funcString, List<int> includedArgIndices) { return getFuncSubString(funcString, includedArgIndices, PAR, DEL); }



        // Private Constructors
        private void constructor1(string funcString, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter)
        {
            this.parenthesisType = parenthesisType;
            this.delimiter = delimiter;
            this.funcString = funcString;
            string openParenthesis = Str.getOpenParenthesis(parenthesisType);
            string closeParenthesis = Str.getCloseParenthesis(parenthesisType);
            int oi = funcString.IndexOf(openParenthesis);
            int ci = Str.findLastIndex(funcString, closeParenthesis);
            if (oi.Equals(-1) && ci.Equals(-1))
            {
                this.funcName = funcString;
                this.argsList = new List<string>();
                return;
            }
            if (!ci.Equals(funcString.Length - 1) || ci < oi) { throw new NotImplementedException(); }
            funcName = Str.left(funcString, oi);
            if (ci == oi + 1)
            {
                this.argsList = new List<string>();
                return;
            }
            string insideParenthesis = Str.mid(funcString, oi + 1, ci - oi - 1);
            this.argsList = StrFuncHelper.getArgs(insideParenthesis, delimiter);
        }
        private void constructor2(string funcName, List<string> argsList, Str.ParenthesisTypes parenthesisType, Str.Delimiter delimiter)
        {
            this.parenthesisType = parenthesisType;
            this.delimiter = delimiter;
            this.funcName = funcName;
            this.funcString = funcName;
            this.argsList = argsList;
            if (argsList.Count == 0) { return; }
            this.funcString += Str.inParenthesis(argsList, parenthesisType, delimiter);
        }
    }
}
