/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Portions created by the Initial Developer are
 * Copyright (C) 2012 the Initial Developer.
 * All Rights Reserved.
 *
 * The Original Code is "http://semi-frame.googlecode.com/svn/trunk/".
 *
 * The Initial Developer of the Original Code is the author below.
 */

/**
 * @file Entity.cs
 * @brief auto generated.
 * @author mornongcloud
 * @date 2011/07/21
 */

using System.Collections.Generic;
using System.Data;
using System.Windows.Forms;

namespace masterframe.model.entity
{
    /// <summary>
    /// SqlServerEntityinstance 
    /// </summary>
    public class Entity : masterframe.model.entity.SqlServerEntity
    {
        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
        /// <summary>
        /// DataTable
        /// </summary>
        public DataTable entities;

        /// <summary>
        /// Validater
        /// </summary>
        public config.Validater validater;

        /// <summary>
        /// 
        /// </summary>
        public config.Column columnsetting;

        // SELECT [PROC], [PARAM], [VAL], [EDIT] FROM [PROC_PARAM]
        string sql_select = "";
        //delete from [PROC_PARAM] where [PROC]=@PROC and [PARAM]=@PARAM
        string sql_delete = "";

        /// <summary>
        /// 
        /// </summary>
        public int keycnt = 1;


        /// <summary>
        /// instance with the data source
        /// </summary>
        /// <param name="p"></param>
        public Entity(string p, string select, string delete = "")
            : base(p)
        {
            this.sql_select = select;
            this.sql_delete = delete;
            this.keycnt = CountChar(delete, '@');

            base.OpenSelect("select 1");// Connection test
        }

        ///// <summary>
        ///// 
        ///// </summary>
        //public void Dispose()
        //{
        //    base.Dispose();
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public DataTable GetTable(string sql)
        {
            var ret = base.OpenSelect(sql);

            return ret;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private string Load(string sql)
        {
            // sqlから抜くしかないらしい DataTable のテーブル名が無いため
            string tblname = "";
            if (0 < sql.Length)
            {
                int stt = sql.IndexOf("FROM");
                tblname = sql.Substring(stt + 5);
                int end = tblname.IndexOf(" ");
                if (0 < end)
                    tblname = tblname.Substring(0, end);
            }

            try
            {
                this.validater = new model.config.Validater(tblname);
                this.columnsetting = new model.config.Column();
            }
            catch (System.Exception e)
            {
                //logger.Error(e.Message, e.InnerException == null ? e : e.InnerException);
                logger.Error(e, e.Message);
                return "Fail to read setting files. [" + e.Message + "] ";
            }
            try
            {
                this.entities = this.GetTable(sql);

                if (0 == this.entities.Rows.Count) return " No data. ";
            }
            catch (System.Exception e)
            {
                //logger.Error(e.Message, e.InnerException == null ? e : e.InnerException);
                logger.Error(e, e.Message);
                return "Fail to read data. [" + e.Message + "] ";
            }
            return "";
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="tbl"></param>
        /// <returns></returns>
        public string Validate(DataTable tbl = null)
        {
            try
            {
                if (null == validater)
                    validater = new model.config.Validater();

                if (null == tbl) tbl = this.entities;

                int i = 0;
                int idx = 0;
                foreach (DataRow row in tbl.Rows)
                {
                    idx++;

                    if (row.RowState == System.Data.DataRowState.Deleted) continue; // delete rows

                    i++;

                    if (row.RowState == System.Data.DataRowState.Unchanged) continue;

                    // 2017.11
                    if (null == row[0] || 0 == row[0].ToString().Length)
                        row[0] = idx;
                    for (int c = 1; c < this.keycnt; c++)
                        if (null == row[c] || 0 == row[c].ToString().Length)
                            row[c] = c;

                    if (tbl.Columns.Contains("EDIT"))
                        //row["EDIT"] = new masterframe.util.DateUtil().ToString();
                        row["EDIT"] = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

                    string val = validater.Validate(this.columnsetting, row);
                    if (0 < val.Length)
                        return val + "(" + i.ToString() + " rows) ";

                }
                return "";
            }
            catch (System.Exception e)
            {
                logger.Error(e, e.Message);
                return "Fail to read data. [" + e.Message + "] ";
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public string Save()
        {
            //string err = this.Validate(this.entities);
            //if (0 < err.Length) return err;

            try
            {
                //if (!base.Update(this.entities)) return "Fail to update data.";
                base.Update(this.entities);

                //string sql_select = "insert into csk.Mobile (MobileId, Type, Number, Name) select MobileId, Type, Number, Name from csk.Vehicle where not exists (select 1 from csk.Mobile where csk.Mobile.MobileId = csk.Vehicle.MobileId)";
                //masterframe.model.entity.SqlServerEntity.Update(cnn, sql_select);
            }
            catch (System.Exception ex)
            {
                logger.Error(ex, ex.Message);
                return "Fail to update data. [" + ex.Message + "]";
            }
            return "";
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public string InsertOrUpdate()
        {
            bool bl = false;
            try
            {
                bl = base.InsertOrUpdate(this.entities);
                //return this.InsertOrUpdateCurrentByMaster();
                if (!bl) return "No data for update.";
                return "";
            }
            catch (System.Exception ex)
            {
                logger.Error(ex, ex.Message);
                return "Fail to update data. [" + ex.Message + "]";
            }
        }

        /// <summary>
        /// 連続削除に対応するため、KEY→位置を取り直す
        /// </summary>
        /// <param name="sql">delete from [PROC_PARAM] where [PROC]=@PROC and [PARAM]=@PARAM</param>
        /// <param name="rows"></param>
        /// <returns></returns>
        public string DeleteByKey(string sql, List<DataGridViewRow> rows)
        {
            try
            {
                //string sql_select = "delete from csk.Vehicle where MobileId=@MobileId";
                //string sql_select = "delete from [CIS].[dbo].[PROC_PARAM] where [PROC]=@PROC and [PARAM]=@PARAM";
                //int keycnt = masterframe.util.StringUtil.CountChar(sql, '@');
                int keycnt = CountChar(sql, '@');

                var delrows = new List<int>();

                int idx = -1;
                foreach (DataRow row in this.entities.Rows)
                {
                    idx++;
                    if (row.RowState == System.Data.DataRowState.Deleted) continue; // 削除済
                    if (row.RowState == System.Data.DataRowState.Added) continue;

                    //string ot1 = row["PROC"].ToString();
                    //if (int.TryParse(, out ot))
                    //{
                    for (int i = 0; i < rows.Count; i++)
                    {
                        bool hit = true; // 全キーがHITする？先頭は必ずキーでなければならない
                        for (int j = 0; j < keycnt; j++)
                        {
                            if (rows[i].Cells[j].Value.ToString() != row[j].ToString())
                            {
                                hit = false;
                                break;
                            }
                        }
                        if (hit)
                        {
                            delrows.Add(idx); //全キーがHIT
                            break;
                        }
                    }
                }

                if (0 == delrows.Count) return "";

                //delete
                //bool ret = masterframe.model.entity.SqlServerEntity.Delete(cnn, this.entities, delrows, sql);
                bool ret = this.Delete(this.entities, delrows, sql);

                return "";
            }
            catch (System.Exception e)
            {
                logger.Error(e, e.Message);
                return "Fail to update data. [" + e.Message + "]";
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="c"></param>
        /// <returns></returns>
        public static int CountChar(string s, char c)
        {
            return s.Length - s.Replace(c.ToString(), "").Length;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        internal string Load()
        {
            return this.Load(this.sql_select);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="delrows"></param>
        /// <returns></returns>
        internal string DeleteByKey(List<DataGridViewRow> delrows)
        {
            return this.DeleteByKey(this.sql_delete, delrows);
        }
    }
}
