using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.ServiceModel;

using BeWo.Data;
using BeWo.Data.Access;
using BeWo.Data.Entities;
using BeWo.Service.ServiceContracts;

using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;

using Utils = BeWo.Service.Core.Utils;

namespace BeWo.Service.ServiceImplementations
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
    public class QueryServiceImp : IQueryService
    {
        public DataTable ExecuteQuery(long pQueryOid, List<QueryParamDC> parameter)
        {
            try
            {
                Query lQuery = DAOFactory.GenericDAO.LoadByID<Query>(pQueryOid);

                string sql = lQuery.Sql;
                if (!String.IsNullOrEmpty(sql))
                {
                    if (parameter != null && parameter.Count > 0)
                    {
                        sql = this.ReplaceQueryParameter(sql, parameter);
                    }

                    return DAOFactory.AdoDAO.ExecuteQuery(sql).Tables[0];
                }
                return new DataTable("emptytable");
            }
            catch (Exception e)
            {
                throw Utils.CreateBeWoFaultException(e);
            }
        }

        public List<QueryDC> GetAllQueriesOfType(QueryType pType)
        {
            try
            {
                return DAOFactory.SearchDAO.FindQuery(pType).Select(
                    q =>
                        {
                            QueryDC queryDC = new QueryDC { Oid = q.Oid.Value, Title = q.Title, ReportTypeName = q.ReportTypeName, UserGroupOids = q.UserGroupOids, Notice = q.Notice };
                            queryDC.IsDirect = (queryDC.Notice == "direct") || String.IsNullOrEmpty(q.Sql);
                            List<QueryParamDC> parameter = new List<QueryParamDC>();
                            foreach (var item in q.Parameter)
                            {
                                QueryParamDC param = new QueryParamDC();
                                param.ParamType = item.Type;
                                param.Name = item.Name;
                                parameter.Add(param);
                            }

                            queryDC.Parameter = parameter;
                            return queryDC;
                        }).ToList();
            }
            catch (Exception e)
            {
                throw Utils.CreateBeWoFaultException(e);
            }
        }

        public string PrepareQueryReport(DataTable dataTable, string id)
        {
            try
            {
                var lResult = id + ".xml";

                var lDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, MultitenancyOperationContextExt.Current.Tenant + @"\temp");
                var lPath = Path.Combine(lDir, lResult);

                BS.Shared.Core.Utils.XMLSerialize(lPath, dataTable);

                return lResult;
            }
            catch (Exception e)
            {
                throw Utils.CreateBeWoFaultException(e);
            }
        }

        // Hack: We don´t use the ReportTypes in Webservice Calls,
        // but the Client needs to know them for Calling ASP Sites
        public void ReportTypes(ReportTypes pType)
        {
        }

        private string GetParamterKeyName(QueryParamDC item)
        {
            return GetParamterKeyName(item.Name);
        }

        private string GetParamterKeyName(string itemName)
        {
            string key = itemName;
            key = key.Replace(" ", "_");

            return key;
        }

        private string ReplaceQueryParameter(string sql, List<QueryParamDC> parameter)
        {
            string newsql = sql;
            foreach (var item in parameter)
            {
                if (item.Value != null)
                {
                    switch (item.ParamType)
                    {
                        case QueryParameterType.SupportConcept:
                            break;
                        case QueryParameterType.Employee:
                        case QueryParameterType.Customer:
                            if (item.Value != null)
                            {
                                long oid;
                                if (Int64.TryParse(item.Value.ToString(), out oid))
                                {
                                    newsql = newsql.Replace(":" + GetParamterKeyName(item), String.Format("{0}", oid));
                                }
                            }

                            break;
                        case QueryParameterType.Month:

                            if (item.Value is DateTime)
                            {
                                DateTime dt = (DateTime)item.Value;

                                newsql = newsql.Replace(":" + GetParamterKeyName(item) + "_MM", String.Format("{0:MM}", dt));
                                newsql = newsql.Replace(":" + GetParamterKeyName(item) + "_Start", String.Format("{0:yyyy-MM}-01", dt));
                                dt = dt.AddMonths(1);
                                newsql = newsql.Replace(":" + GetParamterKeyName(item) + "_End", String.Format("{0:yyyy-MM}-01", dt));
                            }

                            break;
                        case QueryParameterType.Date:
                            break;
                        case QueryParameterType.DateRange:
                            if (item.Value is DateTimeSpan)
                            {
                                DateTimeSpan dts = (DateTimeSpan)item.Value;

                                string[] itemNames = item.Name.Split(new[] { '_' });

                                newsql = newsql.Replace(":" + GetParamterKeyName(itemNames[0]), String.Format("{0:yyyy-MM-dd}", dts.StartDate));
                                if (itemNames.Length > 1)
                                {
                                    DateTime endDate = dts.EndDate;
                                    if (endDate < DateTime.MaxValue.Date)
                                        endDate = endDate.AddDays(1);
                                    newsql = newsql.Replace(":" + GetParamterKeyName(itemNames[1]), String.Format("{0:yyyy-MM-dd}", endDate));
                                }
                            }

                            break;
                        case QueryParameterType.Year:
                            if (item.Value is DateTime)
                            {
                                DateTime dt = (DateTime)item.Value;

                                newsql = newsql.Replace(":year", String.Format("{0:yyyy-MM-dd}", dt));

                                newsql = newsql.Replace(":" + GetParamterKeyName(item) + "_Start", String.Format("{0:yyyy-MM}-01", dt));
                                newsql = newsql.Replace(":" + GetParamterKeyName(item) + "_End", String.Format("{0:yyyy-MM}-01", dt.AddYears(1)));

								newsql = newsql.Replace(":yyyy", String.Format("{0:yyyy}", dt));
                            }
                            break;
                        case QueryParameterType.CurrentUser:
                        case QueryParameterType.CurrentEmployee:
                            if (item.Value != null)
                            {
                                long oid;
                                if (Int64.TryParse(item.Value.ToString(), out oid))
                                {
                                    newsql = newsql.Replace(":" + GetParamterKeyName(item), String.Format("{0}", oid));
                                }
                            }

                            break;
                        case QueryParameterType.ValueListEntryType:
                            if (item.Value != null)
                            {
                                long oid;
                                if (Int64.TryParse(item.Value.ToString(), out oid))
                                {
                                    String[] names = item.Name.Split('_');
                                    newsql = newsql.Replace(":" + names[0], String.Format("{0}", oid));
                                }
                            }

                            break;
                        default:
                            if (item.Value != null)
                            {
                                newsql = newsql.Replace(":" + GetParamterKeyName(item.Name), item.Value.ToString());
                            }
                            break;
                    }
                }
            }

            return newsql;
        }
    }
}