﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sopka.Tools.CodeWriters
{
    public partial class CSharpWriter
    {
        /// <summary>
        /// Universal csharp method (call or definition) arguments
        /// </summary>
        public class MemberArgument
        {
            public string ArgumentName { get; set; }
            public string ArgumentTypeName { get; set; }
            public bool Reference { get; set; }
            public bool Output { get; set; }
            public bool IsNamed { get; set; }
            public object Value { get; set; }

            public string ValueString
            {
                get
                {
                    if (ArgumentTypeName == "string" || (ArgumentTypeName == null && Value is string))
                    {
                        return "\"" + Value.ToString() + "\"";
                    }
                    if (Value is bool)
                    {
                        return Value.ToString().ToLowerInvariant();
                    }
                    return Value.ToString();
                }
            }

            public string GetDeclaration()
            {
                var outRef = Reference ? "ref " : Output ? "out " : string.Empty;
                string vs = string.Empty;
                if (IsNamed)
                    vs = Value != null ? " = " + ValueString : " = null";
                return string.Format($"{outRef}{ArgumentTypeName} {ArgumentName}" + vs);
            }

            public string GetCall()
            {
                var outRef = Reference ? "ref " : Output ? "out " : string.Empty;
                if (outRef != string.Empty)
                {
                    return string.Format($"{outRef}{ArgumentName}");
                }
                else
                {
                    if (IsNamed)
                    {
                        var vs = Value != null ? " = " + ValueString : " = null";
                        return string.Format($"{ArgumentName}" + vs);
                    }
                    else
                    {
                        return ValueString;
                    }
                }
            }

            public static MemberArgument CreateRefValue(string argumentName)
            {
                return new MemberArgument { Reference = true, ArgumentName = argumentName };
            }

            public static MemberArgument CreateOutValue(string argumentName)
            {
                return new MemberArgument { Output = true, ArgumentName = argumentName };
            }

            public static MemberArgument CreateValue(object value, bool isNamed = false, string argumentName = null, string dataType = null)
            {
                return new MemberArgument { Value = value, IsNamed = isNamed, ArgumentName = argumentName, ArgumentTypeName = dataType };
            }

            public static MemberArgument CreateValue(string dataType, object value)
            {
                return new MemberArgument { Value = value, IsNamed = false, ArgumentName = null, ArgumentTypeName = dataType };
            }


            public static MemberArgument CreateRefParam(string dataType, string argumentName, bool isOptional = false, object defaultValue = null)
            {
                return new MemberArgument { Reference = true, ArgumentTypeName = dataType, ArgumentName = argumentName, Value = defaultValue, IsNamed = isOptional };
            }

            public static MemberArgument CreateOutParam(string dataType, string argumentName, bool isOptional = false, object defaultValue = null)
            {
                return new MemberArgument { Output = true, ArgumentTypeName = dataType, ArgumentName = argumentName, Value = defaultValue, IsNamed = isOptional };
            }

            public static MemberArgument CreateParam(string dataType, string argumentName, bool isOptional = false, object defaultValue = null)
            {
                return new MemberArgument { ArgumentTypeName = dataType, ArgumentName = argumentName, Value = defaultValue, IsNamed = isOptional };
            }

            public static implicit operator MemberArgument(string value)
            {
                var arg = CreateValue(value);
                arg.ArgumentTypeName = "string";
                return arg;
            }

            public static implicit operator MemberArgument(bool value)
            {
                return CreateValue(value);
            }

            public static implicit operator MemberArgument(int value)
            {
                return CreateValue(value);
            }

            public static implicit operator MemberArgument(DateTime value)
            {
                return CreateValue(value);
            }

            public static implicit operator MemberArgument(byte value)
            {
                return CreateValue(value);
            }

            public static implicit operator string(MemberArgument arg)
            {
                return arg.GetCall();
            }
        }
    }

}
