using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Windows.Forms;
using FCOMMON.Models;
using System.Data;
using System.Reflection;

namespace FCOMMON
{
    public static partial class DBM
    {
        public static SqlConnection getCn()
        {
            string cs = FCOMMON.info.CS;
            SqlConnection cn = new SqlConnection();
            cn.ConnectionString = cs;
            return cn;
        }

        public static void GetPurchaseWaitCount(string gcode, out int cnt1, out int cnt2)
        {
            cnt1 = 0;
            cnt2 = 0;
            var cn = getCn();
            var sql1 = "select count(*) from Purchase where gcode = @gcode" +
            " and state like '--%'" +
            " and pdate >= @date";

            var sql2 = "select count(*) from EETGW_PurchaseCR where gcode = @gcode" +
            " and state like '--%'" +
            " and pdate >=  @date";

            cn.Open();

            var cmd = new System.Data.SqlClient.SqlCommand(sql1, cn);
            cmd.Parameters.Add("gcode", SqlDbType.VarChar).Value = gcode;
            cmd.Parameters.Add("date", SqlDbType.VarChar).Value = DateTime.Now.AddYears(-1).ToString("yyyy-MM-dd");
            cnt1 = (int)cmd.ExecuteScalar();
            cmd.CommandText = sql2;
            cnt2 = (int)cmd.ExecuteScalar();
            cn.Dispose();

        }


        public static UserModel GetUserInfo(string uid)
        {
            var retval = new UserModel();
            var cn = getCn();

            var sql = "select * from Users where id = @id";
            var cmd = new System.Data.SqlClient.SqlCommand(sql, cn);
            cmd.Parameters.Add("id", SqlDbType.VarChar).Value = uid;
            cn.Open();
            var rdr = cmd.ExecuteReader();
            var cnt = 0;
            while (rdr.Read())
            {
                retval.name = rdr["name"].ToString();
                retval.password = rdr["password"].ToString();
                retval.id = rdr["id"].ToString();
                retval.email = rdr["email"].ToString();
                retval.hp = rdr["email"].ToString();
                retval.tel = rdr["tel"].ToString();
                retval.grade = rdr["grade"].ToString();
                cnt += 1;
            }

            cn.Dispose();
            if (cnt == 0) return null;
            return retval;
        }

        public static UserGroupModel GetUserGroup(string gcode)
        {
            var retval = new UserGroupModel();
            var cn = getCn();

            var sql = "select gcode,dept,isnull(permission,0) as permission from UserGroup where gcode = @gcode";
            var cmd = new System.Data.SqlClient.SqlCommand(sql, cn);
            cmd.Parameters.Add("gcode", SqlDbType.VarChar).Value = gcode;
            cn.Open();
            var rdr = cmd.ExecuteReader();
            var cnt = 0;
            while (rdr.Read())
            {
                retval.gcode = rdr["gcode"].ToString();
                retval.name = rdr["dept"].ToString();
                retval.perm = int.Parse(rdr["permission"].ToString());
                cnt += 1;
            }
            cn.Dispose();
            if (cnt == 0) return null;
            return retval;
        }
        /// <summary>
        /// 입력된 id의 그룹정보를 반환
        /// </summary>
        /// <param name="gcode"></param>
        /// <param name="uid"></param>
        /// <returns></returns>
        public static GroupUserModel GetGroupUser(string gcode, string uid)
        {
            var retval = new GroupUserModel();
            var cn = getCn();


            //          public string name { get; set; }
            //public string email { get; set; }
            //public bool useAccount { get; set; }
            //public bool useJobReport { get; set; }



            var sql = "select gcode,id,level,isnull(Process,'') as Process ,isnull(name,'') as name,isnull(useUserState,0) as useAccount,isnull(useJobReport,0) as useJobReport " +
                " from vGroupUser where " +
                " gcode = @gcode " +
                " and id =  @uid";
            var cmd = new System.Data.SqlClient.SqlCommand(sql, cn);
            cmd.Parameters.Add("gcode", SqlDbType.VarChar).Value = gcode;
            cmd.Parameters.Add("uid", SqlDbType.VarChar).Value = uid;
            cn.Open();
            var rdr = cmd.ExecuteReader();
            var cnt = 0;
            while (rdr.Read())
            {
                retval.Gcode = rdr["gcode"].ToString();
                retval.uid = rdr["id"].ToString();
                retval.level = int.Parse(rdr["level"]?.ToString() ?? "0");
                retval.Process = rdr["Process"].ToString();
                retval.name = rdr["name"].ToString();
                retval.useAccount = rdr["useAccount"].ToString() == "True";
                retval.useJobReport = rdr["useJobReport"].ToString() == "True";
                cnt += 1;
            }


            cn.Dispose();
            if (cnt == 0) return null;
            return retval;
        }
        public static List<GroupUserModel> GetGroupUser(string gcode)
        {
            var retval = new List<GroupUserModel>();
            var cn = getCn();


            //          public string name { get; set; }
            //public string email { get; set; }
            //public bool useAccount { get; set; }
            //public bool useJobReport { get; set; }



            var sql = "select gcode,id ,level,isnull(Process,'') as Process ,isnull(name,'') as name,isnull(useUserState,0) as useAccount,isnull(useJobReport,0) as useJobReport " +
                " from vGroupUser " +
                " where gcode = @gcode " +
                " order by isnull(Process,'')+isnull(name,'')";

            var cmd = new System.Data.SqlClient.SqlCommand(sql, cn);
            cmd.Parameters.Add("gcode", SqlDbType.VarChar).Value = gcode;
            cn.Open();
            var rdr = cmd.ExecuteReader();
            var cnt = 0;
            while (rdr.Read())
            {
                retval.Add(new GroupUserModel
                {
                    Gcode = rdr["gcode"].ToString(),
                    uid = rdr["id"].ToString(),
                    level = int.Parse(rdr["level"]?.ToString() ?? "0"),
                    Process = rdr["Process"].ToString(),
                    name = rdr["name"].ToString(),
                    useAccount = rdr["useAccount"].ToString() == "True",
                    useJobReport = rdr["useJobReport"].ToString() == "True",
                });
                cnt += 1;
            }


            cn.Dispose();
            if (cnt == 0) return null;
            return retval;
        }


        public static List<UserGroupModel> GetUserGroups()
        {
            var cn = getCn();
            cn.Open();

            List<UserGroupModel> retval = new List<UserGroupModel>();
            var sql = " select gcode,dept,permission,managerinfo,devinfo,usemail" +
                      " from UserGroup " +
                      " order by usemail desc,dept";

            var cmd = new SqlCommand(sql, cn);
            try
            {
                var rdr = cmd.ExecuteReader();
                while (rdr.Read())
                {
                    retval.Add(new UserGroupModel
                    {
                        gcode = rdr["gcode"]?.ToString() ?? string.Empty,
                        name = rdr["dept"]?.ToString() ?? string.Empty,
                        perm = int.Parse(rdr["permission"]?.ToString() ?? "0"),
                    });
                }
            }
            catch
            {

            }
            cn.Close();
            cn.Dispose();
            return retval;
        }


        public static List<string> GetItemStorageList()
        {


            var cn = getCn();
            cn.Open();

            List<string> retval = new List<string>();
            var sql = "SELECT place FROM Inventory  WITH (nolock) WHERE(gcode = @gcode) AND(ISNULL(place, '') <> '') GROUP BY place ORDER BY place";
            var cmd = new SqlCommand(sql, cn);
            cmd.Parameters.Add("gcode", System.Data.SqlDbType.VarChar).Value = FCOMMON.info.Login.gcode;
            try
            {
                var rdr = cmd.ExecuteReader();
                while (rdr.Read())
                {
                    retval.Add(rdr[0].ToString());
                }
            }
            catch
            {

            }

            cn.Close();
            cn.Dispose();
            return retval;
        }


        /// <summary>
        /// EETGW_GroupUser 테이블에서 활성화된 사용자의 process 목록을 가져온다
        /// </summary>
        /// <returns></returns>
        public static List<string> GroupUserProcessList()
        {


            var cn = getCn();
            cn.Open();

            List<string> retval = new List<string>();
            var sql = "SELECT Process FROM EETGW_GroupUser WITH (nolock) WHERE  (ISNULL(Process, '') <> '') AND (gcode = @gcode) and useJobReport = 1 and useUserState =1 GROUP BY Process ORDER BY Process";
            var cmd = new SqlCommand(sql, cn);
            cmd.Parameters.Add("gcode", System.Data.SqlDbType.VarChar).Value = FCOMMON.info.Login.gcode;
            try
            {
                var rdr = cmd.ExecuteReader();
                while (rdr.Read())
                {
                    retval.Add(rdr[0].ToString());
                }
            }
            catch
            {

            }

            cn.Close();
            cn.Dispose();
            return retval;
        }




        public static byte[] getImagByteArray(System.Drawing.Image img)
        {
            if (img == null || img.Width < 1 || img.Height < 1) return null;

            //이미지가 640보다 크면 조정한다.
            if (img.Width > 640)
            {
                var newrate = (640.0 / img.Width * 1.0);
                var newheight = (int)(img.Height * newrate); //높이값 다시 계산
                var newimg = new System.Drawing.Bitmap(640, newheight);
                var g = System.Drawing.Graphics.FromImage(newimg);
                g.DrawImage(img, new System.Drawing.Rectangle(0, 0, 640, newheight));
                g.Dispose();
                img = (System.Drawing.Image)(newimg.Clone());

            }
            else if (img.Height > 480)
            {
                var newrate = (480.0 / img.Height * 1.0);
                var newwidth = (int)(img.Width * newrate); //높이값 다시 계산
                var newimg = new System.Drawing.Bitmap(newwidth, 480);
                var g = System.Drawing.Graphics.FromImage(newimg);
                g.DrawImage(img, new System.Drawing.Rectangle(0, 0, newwidth, 480));
                g.Dispose();
                img = (System.Drawing.Image)(newimg.Clone());
            }



            System.IO.MemoryStream sm = new System.IO.MemoryStream();
            img.Save(sm, System.Drawing.Imaging.ImageFormat.Jpeg);
            var buffer = sm.GetBuffer();
            sm.Dispose();
            return buffer;
        }
        public static Boolean setImageData(System.Drawing.Bitmap img, string table, string field, int idx)
        {
            return setImageData((System.Drawing.Image)img, table, field, idx);
        }
        public static Boolean setImageData(System.Drawing.Image img, string table, string field, int idx)
        {
            if (img == null || img.Width < 1 || img.Height < 1) return false;

            //이미지가 640보다 크면 조정한다.
            if (img.Width > 640)
            {
                var newrate = (640.0 / img.Width * 1.0);
                var newheight = (int)(img.Height * newrate); //높이값 다시 계산
                var newimg = new System.Drawing.Bitmap(640, newheight);
                var g = System.Drawing.Graphics.FromImage(newimg);
                g.DrawImage(img, new System.Drawing.Rectangle(0, 0, 640, newheight));
                g.Dispose();
                img = (System.Drawing.Image)(newimg.Clone());

            }
            else if (img.Height > 480)
            {
                var newrate = (480.0 / img.Height * 1.0);
                var newwidth = (int)(img.Width * newrate); //높이값 다시 계산
                var newimg = new System.Drawing.Bitmap(newwidth, 480);
                var g = System.Drawing.Graphics.FromImage(newimg);
                g.DrawImage(img, new System.Drawing.Rectangle(0, 0, newwidth, 480));
                g.Dispose();
                img = (System.Drawing.Image)(newimg.Clone());
            }

            var cn = getCn();
            cn.Open();

            Boolean retval = false;
            string sql = "update  " + table + " set " + field + " = @data" + " where idx = @idx";
            var cmd = new SqlCommand(sql, cn);

            System.IO.MemoryStream sm = new System.IO.MemoryStream();
            img.Save(sm, System.Drawing.Imaging.ImageFormat.Jpeg);
            var buffer = sm.GetBuffer();
            sm.Dispose();

            cmd.Parameters.Add(new SqlParameter("idx", idx));
            cmd.Parameters.Add(new SqlParameter("data", buffer));
            try
            {
                cmd.ExecuteNonQuery();
                retval = true;
            }
            catch
            {

            }

            cn.Close();
            cn.Dispose();
            return retval;
        }


        public class buyinfo
        {
            public int Request { get; set; }
            public int PR { get; set; }
            public int PO { get; set; }
            public int Received { get; set; }
            //public int Cancled { get; set; }
            public int Total_Request { get; set; }
            public int Total_Ipko { get; set; }
            public int Total_Remain { get; set; }

        }

        public static buyinfo GetPartBuyInfo(int project, string sid = null)
        {
            var sql =
                " select " +
                " isnull(sum(case when[state] = 'PR' then 0 when[state] = 'PO' then 0 when[state] = 'Received' then 0 when[state] = 'Cancled' then 0 else pumqtyreq end),0) as Request," +
                " isnull(sum(case when[state] = 'PR' then pumqty else 0 end),0) as PR," +
                " isnull(sum(case when[state] = 'PO' then pumqty else 0 end),0) as PO," +
                " isnull(sum(case when[state] = 'Received' then inqty else 0 end),0) as Received," +
                " isnull(sum(pumqtyreq),0)  as Total_Request," +
                " isnull(sum(inqty),0) as Total_Buy," +
                " isnull(sum(pumqtyreq) - sum(inqty),0) as Total_Remain" +
                " from EETGW_PurchaseCR with(nolock) " +
                " where gcode = @gcode and state <> 'Cancled'" +
                " and projectidx = @project" +
                 (sid == null ? string.Empty : " and sid = @sid") +
                " and isnull(isdel,0) = 0" +
                " union all" +
                " select " +
                " isnull(sum(case when[state] = 'PR' then 0 when[state] = 'PO' then 0 when[state] = 'Received' then 0 when[state] = 'Cancled' then 0 else pumqtyreq end),0) as Request," +
                " isnull(sum(case when[state] = 'PR' then pumqty else 0 end),0) as PR," +
                " isnull(sum(case when[state] = 'PO' then pumqty else 0 end),0) as PO," +
                " isnull(sum(case when[state] = 'Received' then inqty else 0 end),0) as Received," +
                " isnull(sum(pumqtyreq),0) as Total_Request," +
                " isnull(sum(inqty),0) as Total_Buy," +
                " isnull(sum(pumqtyreq) - sum(inqty),0) as Total_Remain" +
                " from Purchase with(nolock) " +
                " where gcode = @gcode and state <> 'Cancled'" +
                " and projectidx = @project" +
                 (sid == null ? string.Empty : " and sid = @sid") +
                " and isnull(isdel,0) = 0";


            var cn = getCn();
            var cmd = new SqlCommand(sql, cn);
            cmd.Parameters.Add("gcode", System.Data.SqlDbType.VarChar).Value = FCOMMON.info.Login.gcode;
            cmd.Parameters.Add("project", System.Data.SqlDbType.Int).Value = project;
            if (sid != null)
                cmd.Parameters.Add("sid", System.Data.SqlDbType.VarChar).Value = sid;
            cn.Open();

            var rdr = cmd.ExecuteReader();
            var retval = new buyinfo();
            while (rdr.Read())
            {
                var o_request = rdr["Request"];
                var o_pr = rdr["PR"];
                var o_po = rdr["PO"];
                var o_received = rdr["Received"];
                //var o_cancled = rdr["Cancled"];

                var o_totalrequest = rdr["Total_Request"];
                var o_totalbuy = rdr["Total_Buy"];
                var o_totalremain = rdr["Total_Remain"];

                if (o_request != null) retval.Request += int.Parse(o_request.ToString());
                if (o_pr != null) retval.PR += int.Parse(o_pr.ToString());
                if (o_po != null) retval.PO += int.Parse(o_po.ToString());
                if (o_received != null) retval.Received += int.Parse(o_received.ToString());
                //if (o_cancled != null) retval.Cancled = int.Parse(o_cancled.ToString());
                if (o_totalrequest != null) retval.Total_Request += int.Parse(o_totalrequest.ToString());
                if (o_totalbuy != null) retval.Total_Ipko += int.Parse(o_totalbuy.ToString());
                if (o_totalremain != null) retval.Total_Remain += int.Parse(o_totalremain.ToString());
            }
            rdr.Close();
            cn.Dispose();
            return retval;
        }

        public static float GetProjectBuyInfo(int project)
        {
            var sql =
                " select isnull(((sum((case when isnull(pumqty,0) = isnull(inqty,0) then 1 else 0 end))*1.0) / count(*))*100,0)" +
                " from EETGW_PurchaseCR  WITH (nolock) " +
                " where gcode = @gcode" +
                " and projectidx = @project" +
                " and isnull(isdel,0) = 0" +
                " and isnull([state],'') <> 'Cancled'";

            var cn = getCn();
            var cmd = new SqlCommand(sql, cn);
            cmd.Parameters.Add("gcode", System.Data.SqlDbType.VarChar).Value = FCOMMON.info.Login.gcode;
            cmd.Parameters.Add("project", System.Data.SqlDbType.Int).Value = project;
            cn.Open();

            var rdr = cmd.ExecuteScalar();
            float retval = float.Parse(rdr.ToString());
            cn.Dispose();
            return retval;
        }



        /// <summary>
        /// 지정쿼리를 실행합니다.
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        public static int ExecuteNonQuery(string sql)
        {
            var cn = getCn();
            cn.Open();
            var cmd = new SqlCommand(sql, cn);
            var retval = cmd.ExecuteNonQuery();
            cn.Close();
            cn.Dispose();
            return retval;
        }
        public static int ExecuteScalarI(string sql)
        {
            var cn = getCn();
            cn.Open();
            var cmd = new SqlCommand(sql, cn);
            var retval = (int)(cmd.ExecuteScalar());
            cn.Close();
            cn.Dispose();
            return retval;
        }
        public static string ExecuteScalar(string sql)
        {
            var cn = getCn();
            cn.Open();
            var cmd = new SqlCommand(sql, cn);
            var retval = cmd.ExecuteScalar().ToString();
            cn.Close();
            cn.Dispose();
            return retval;
        }
        public static System.Drawing.Image GetImageData(string table, string field, int idx)
        {
            var cn = getCn();
            cn.Open();


            string sql = "select " + field + " from " + table + " where idx = " + idx.ToString();
            var cmd = new SqlCommand(sql, cn);
            var data = cmd.ExecuteScalar() as byte[];
            System.Drawing.Bitmap bmp = null;
            if (data != null)
            {
                System.IO.MemoryStream ms = new System.IO.MemoryStream(data);
                bmp = new System.Drawing.Bitmap(ms, true);
                ms.Dispose();
            }
            cn.Close();
            cn.Dispose();
            return bmp;
        }

        public static string GetMaxVersion()
        {
            try
            {
                var sql = "select max(prgmVersion) from ProgramUser  WITH (nolock) " +
                " where prgmName = 'Amkor K4-EET GroupWare'";
                return ExecuteScalar(sql);
            }
            catch
            {
                return string.Empty;
            }
        }

        public static bool AddMagamList(string mon)
        {
            var gcode = FCOMMON.info.Login.gcode;


            //해당기간내의 마감 자료를 조회해서 넣는다.
            var cn = getCn();
            cn.Open();

            var retval = new List<string>();
            string sql = "select count(*) from EETGW_Magam   WITH (nolock) where  gcode=@gcode and pdate = @pdate";
            var cmd = new SqlCommand(sql, cn);
            cmd.Parameters.Add("gcode", System.Data.SqlDbType.VarChar).Value = gcode;
            cmd.Parameters.Add("pdate", System.Data.SqlDbType.VarChar).Value = mon;
            var datacnt = int.Parse(cmd.ExecuteScalar().ToString());
            if (datacnt == 0)
            {
                sql = "insert into EETGW_Magam(gcode,pdate,wdate,wuid) values(@gcode,@pdate,@wdate,@wuid)";
                cmd.CommandText = sql;
                cmd.Parameters.Add("wdate", System.Data.SqlDbType.DateTime).Value = DateTime.Now;
                cmd.Parameters.Add("wuid", System.Data.SqlDbType.VarChar).Value = FCOMMON.info.Login.no;
                datacnt = cmd.ExecuteNonQuery();
            }

            cn.Close();
            cn.Dispose();
            return datacnt == 1;

        }
        public static bool DelMagamList(string mon)
        {
            var gcode = FCOMMON.info.Login.gcode;

            //해당기간내의 마감 자료를 조회해서 넣는다.
            var cn = getCn();
            cn.Open();

            var retval = new List<string>();
            string sql = "delete from EETGW_Magam where  gcode=@gcode and pdate = @pdate";
            var cmd = new SqlCommand(sql, cn);
            cmd.Parameters.Add("gcode", System.Data.SqlDbType.VarChar).Value = gcode;
            cmd.Parameters.Add("pdate", System.Data.SqlDbType.VarChar).Value = mon;
            var datacnt = int.Parse(cmd.ExecuteNonQuery().ToString());
            cn.Close();
            cn.Dispose();
            return datacnt == 1;

        }
        public static List<string> GetMagamList()
        {
            var gcode = FCOMMON.info.Login.gcode;
            var sdate = DateTime.Now.AddMonths(-6).ToString("yyyy-MM");
            var edate = DateTime.Now.AddMonths(1).ToString("yyyy-MM");

            //해당기간내의 마감 자료를 조회해서 넣는다.
            var cn = getCn();
            cn.Open();

            var retval = new List<string>();

            string sql = "select pdate" +
                " from EETGW_Magam  WITH (nolock) " +
                " where gcode=@gcode and   pdate  between @sdate and @edate and isnull(pdate,'') <> ''";

            var cmd = new SqlCommand(sql, cn);
            cmd.Parameters.Add("gcode", System.Data.SqlDbType.VarChar).Value = gcode;
            cmd.Parameters.Add("sdate", System.Data.SqlDbType.VarChar).Value = sdate;
            cmd.Parameters.Add("edate", System.Data.SqlDbType.VarChar).Value = edate;

            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                retval.Add(rdr[0].ToString());
            }

            cn.Close();
            cn.Dispose();
            return retval;

        }

        public static bool GetMagamStatus(DateTime mon)
        {
            return GetMagamStatus(mon.ToString("yyyy-MM"));
        }

        /// <summary>
        /// 머감상태를 확인합니다.
        /// </summary>
        /// <param name="mon">yyyy-MM</param>
        /// <returns></returns>
        public static bool GetMagamStatus(string mon)
        {
            var gcode = FCOMMON.info.Login.gcode;
            var sdate = mon;// DateTime.Now.AddMonths(-6).ToString("yyyy-MM");
                            //var edate = DateTime.Now.AddMonths(1).ToString("yyyy-MM");

            //해당기간내의 마감 자료를 조회해서 넣는다.
            var cn = getCn();
            cn.Open();

            var retval = new List<string>();

            string sql = "select count(*)" +
                " from EETGW_Magam  WITH (nolock) " +
                " where gcode=@gcode and   pdate  = @sdate";

            var cmd = new SqlCommand(sql, cn);
            cmd.Parameters.Add("gcode", System.Data.SqlDbType.VarChar).Value = gcode;
            cmd.Parameters.Add("sdate", System.Data.SqlDbType.VarChar).Value = sdate;

            var cnt = int.Parse(cmd.ExecuteScalar().ToString());


            cn.Close();
            cn.Dispose();
            return cnt > 0;

        }

        public static ItemModel getLastPurchaseInfo(int idx)
        {
            var cn = getCn();
            cn.Open();

            var retval = new ItemModel();
            retval.idx = -1;

            string sql = "select isnull(max(idx),-1) from Purchase where pumidx = " + idx.ToString();
            var cmd = new SqlCommand(sql, cn);
            int maxidx = int.Parse(cmd.ExecuteScalar().ToString());
            if (maxidx == -1) return retval;

            cmd.CommandText = "select * from Purchase  WITH (nolock) where idx = " + maxidx.ToString();
            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                retval.idx = (int)rdr["idx"];
                if (rdr["sid"] != DBNull.Value) retval.sid = rdr["sid"].ToString();
                if (rdr["pumscale"] != DBNull.Value) retval.model = rdr["pumscale"].ToString();
                if (rdr["supply"] != DBNull.Value) retval.supply = rdr["supply"].ToString();
                if (rdr["supplyidx"] != DBNull.Value) retval.supplyidx = int.Parse(rdr["supplyidx"].ToString());
                else retval.supplyidx = -1;

                if (rdr["pumname"] != DBNull.Value) retval.name = rdr["pumname"].ToString();
                if (rdr["pumunit"] != DBNull.Value) retval.unit = rdr["pumunit"].ToString();
                if (rdr["project"] != DBNull.Value) retval.project = rdr["project"].ToString();

                if (rdr["pumprice"] != DBNull.Value) retval.price = rdr["pumprice"].ToString();
                else retval.price = "0";

                if (rdr["pumqty"] != DBNull.Value) retval.qty = int.Parse(rdr["pumqty"].ToString());
                else retval.qty = 0;

            }

            cn.Close();
            cn.Dispose();
            return retval;
        }

        public static ItemModel getLastPurchaseCRInfo(int idx)
        {
            var cn = getCn();
            cn.Open();

            var retval = new ItemModel();
            retval.idx = -1;

            string sql = "select isnull(max(idx),-1) from EETGW_PurchaseCR  WITH (nolock) where pumidx = " + idx.ToString();
            var cmd = new SqlCommand(sql, cn);
            int maxidx = int.Parse(cmd.ExecuteScalar().ToString());
            if (maxidx == -1) return retval;

            cmd.CommandText = "select * from EETGW_PurchaseCR  WITH (nolock) where idx = " + maxidx.ToString();
            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                retval.idx = (int)rdr["idx"];
                if (rdr["sid"] != DBNull.Value) retval.sid = rdr["sid"].ToString();
                if (rdr["pumscale"] != DBNull.Value) retval.model = rdr["pumscale"].ToString();
                if (rdr["supply"] != DBNull.Value) retval.supply = rdr["supply"].ToString();
                if (rdr["supplyidx"] != DBNull.Value) retval.supplyidx = int.Parse(rdr["supplyidx"].ToString());
                else retval.supplyidx = -1;

                if (rdr["pumname"] != DBNull.Value) retval.name = rdr["pumname"].ToString();
                if (rdr["pumunit"] != DBNull.Value) retval.unit = rdr["pumunit"].ToString();
                if (rdr["project"] != DBNull.Value) retval.project = rdr["project"].ToString();

                if (rdr["pumprice"] != DBNull.Value) retval.price = rdr["pumprice"].ToString();
                else retval.price = "0";

                if (rdr["pumqty"] != DBNull.Value) retval.qty = int.Parse(rdr["pumqty"].ToString());
                else retval.qty = 0;

            }

            cn.Close();
            cn.Dispose();
            return retval;
        }


        public static Dictionary<string, string> GetUserHolidayJan(string gcode, string uid, string pdate)
        {
            var cn = getCn();
            cn.Open();

            var retval = new Dictionary<string, string>();
            var dt = DateTime.Parse(pdate);
            var dtys = dt.Year.ToString("0000") + "-01-01";

            string sql = "select isnull(cate,'--'), " +
                " isnull(sum(termdr),0), " +
                " isnull(sum(term),0), " +
                " isnull(sum(termdr)-sum(term),0) ," +
                " round(isnull(sum(drtime),0),2)," +
                " round(isnull(sum(crtime),0),2)," +
                " round(isnull(sum(drtime)-sum(crtime),0),2) as JanTime" +
                " from Holyday  WITH (nolock) " +
                " where gcode=@gcode and  uid = @uid and sdate  between @sdate and @edate group by cate order by cate";

            var cmd = new SqlCommand(sql, cn);
            cmd.Parameters.Add("gcode", System.Data.SqlDbType.VarChar).Value = gcode;
            cmd.Parameters.Add("uid", System.Data.SqlDbType.VarChar).Value = uid;
            cmd.Parameters.Add("sdate", System.Data.SqlDbType.VarChar).Value = dtys;
            cmd.Parameters.Add("edate", System.Data.SqlDbType.VarChar).Value = pdate;



            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                var drtime = (double)rdr[4];
                var crtime = (double)rdr[5];
                retval.Add(rdr[0].ToString(), $"{rdr[1]}|{rdr[2]}|{rdr[3]}|{rdr[4]}|{rdr[5]}|{rdr[6]}");
            }

            cn.Close();
            cn.Dispose();
            return retval;
        }

        /// <summary>
        /// 서플라이정보를 찾습니다. 1개의데이터가 검색된 경우에만 사용 됩니다.
        /// </summary>
        /// <param name="nameLike"></param>
        /// <param name="idx"></param>
        /// <param name="nameK"></param>
        /// <param name="nameE"></param>
        /// <returns></returns>
        public static Boolean getFindSupply(string nameLike, out int idx, out string nameK, out string nameE)
        {
            idx = -1;
            nameE = "";
            nameK = "";

            var cn = getCn();
            cn.Open();

            string sql = "select idx,name,name2 from Customs WITH (nolock) where (name like '%SEEMAX%' or name2 like '%{0}%')";
            sql = string.Format(sql, nameLike);
            var cmd = new SqlCommand(sql, cn);
            var rdr = cmd.ExecuteReader();

            int cnt = 0;
            while (rdr.Read())
            {
                idx = (int)rdr["idx"];
                if (rdr["name"] != DBNull.Value) nameK = rdr["name"].ToString();
                if (rdr["name2"] != DBNull.Value) nameE = rdr["name2"].ToString();
                cnt += 1;
            }

            cn.Close();
            cn.Dispose();
            return cnt == 1;
        }

        /// <summary>
        /// 프로젝트 주간내역을 추가합니다
        /// </summary>
        /// <param name="ProjectIdx"></param>
        /// <param name="Message"></param>
        /// <returns></returns>
        public static Boolean addProjectHistory(int ProjectIdx, string pdate, string Message, string rtf)
        {

            var cn = getCn();
            cn.Open();

            string sql =
                "insert into ProjectsHistory(pidx,pdate,remark,remark2,wuid,wdate)" +
                " values(@pidx,@pdate,@remark,@remark2,@wuid,@wdate)";

            var cmd = new SqlCommand(sql, cn);
            cmd.Parameters.Add(new SqlParameter("pidx", ProjectIdx));
            cmd.Parameters.Add(new SqlParameter("pdate", pdate));
            cmd.Parameters.Add(new SqlParameter("remark", Message));
            cmd.Parameters.Add(new SqlParameter("remark2", rtf));
            cmd.Parameters.Add(new SqlParameter("wuid", FCOMMON.info.Login.no));
            cmd.Parameters.Add(new SqlParameter("wdate", DateTime.Now));
            var cnt = cmd.ExecuteNonQuery();

            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            return cnt == 1;
        }

        public static ItemModel getItemInfo(int idx)
        {
            var cn = getCn();
            cn.Open();

            var retval = new ItemModel();
            retval.idx = -1;

            string sql = "select * from Items   WITH (nolock) where gcode='" + FCOMMON.info.Login.gcode + "' and  idx = " + idx.ToString();
            var cmd = new SqlCommand(sql, cn);
            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                retval.idx = (int)rdr["idx"];
                if (rdr["sid"] != DBNull.Value) retval.sid = rdr["sid"].ToString();
                if (rdr["model"] != DBNull.Value) retval.model = rdr["model"].ToString();
                if (rdr["supply"] != DBNull.Value) retval.supply = rdr["supply"].ToString();
                if (rdr["supplyidx"] != DBNull.Value) retval.supplyidx = int.Parse(rdr["supplyidx"].ToString());

                if (rdr["name"] != DBNull.Value) retval.name = rdr["name"].ToString();
                if (rdr["unit"] != DBNull.Value) retval.unit = rdr["unit"].ToString();
                if (rdr["scale"] != DBNull.Value) retval.scale = float.Parse(rdr["scale"].ToString());
                if (rdr["price"] != DBNull.Value) retval.price = rdr["price"].ToString();

            }

            cn.Close();
            cn.Dispose();
            return retval;
        }
        public static int addItemInfo(ItemModel info)
        {
            int retval = -1;
            var cn = getCn();
            cn.Open();

            string sql = "insert into Items" +
                " ([gcode],[cate],[sid],[model],[supply],[supplyidx],[name],[unit],[scale],[price],[wuid],[wdate])" +
                " values " +
                " (@gcode,@cate,@sid,@model,@supply,@supplyidx,@name,@unit,@scale,@price,@wuid,@wdate)";

            var cmd = new SqlCommand(sql, cn);
            cmd.Parameters.Add(new SqlParameter("@gcode", FCOMMON.info.Login.gcode));
            cmd.Parameters.Add(new SqlParameter("@cate", "etc"));
            cmd.Parameters.Add(new SqlParameter("@sid", info.sid));
            cmd.Parameters.Add(new SqlParameter("@model", info.model));
            cmd.Parameters.Add(new SqlParameter("@supply", info.supply));
            cmd.Parameters.Add(new SqlParameter("@supplyidx", info.supplyidx));
            cmd.Parameters.Add(new SqlParameter("@name", info.name));
            cmd.Parameters.Add(new SqlParameter("@unit", info.unit));
            cmd.Parameters.Add(new SqlParameter("@scale", info.scale));
            cmd.Parameters.Add(new SqlParameter("@price", info.price));
            cmd.Parameters.Add(new SqlParameter("@wuid", FCOMMON.info.Login.no));
            cmd.Parameters.Add(new SqlParameter("@wdate", DateTime.Now));

            var iCnt = cmd.ExecuteNonQuery();
            if (iCnt == 1)
            {
                cmd.CommandText = "select isnull(idx,-1) from Items  WITH (nolock) where gcode=@gcode and  [sid] = @sid";
                cmd.Parameters.Clear();
                cmd.Parameters.Add(new SqlParameter("gcode", FCOMMON.info.Login.gcode));
                cmd.Parameters.Add(new SqlParameter("sid", info.sid));
                retval = (int)cmd.ExecuteScalar();
            }

            cn.Close();
            cn.Dispose();
            return retval;
        }
        public static ItemModel getItemInfo(string sid)
        {
            var cn = getCn();
            cn.Open();

            var retval = new ItemModel();
            retval.idx = -1;

            string sql = "select * from Items  WITH (nolock) where [gcode] = '" + FCOMMON.info.Login.gcode + "' and  [sid] = '" + sid + "'";
            var cmd = new SqlCommand(sql, cn);
            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                retval.idx = (int)rdr["idx"];
                if (rdr["sid"] != DBNull.Value) retval.sid = rdr["sid"].ToString();
                if (rdr["model"] != DBNull.Value) retval.model = rdr["model"].ToString();
                if (rdr["supply"] != DBNull.Value) retval.supply = rdr["supply"].ToString();
                if (rdr["supplyidx"] != DBNull.Value) retval.supplyidx = int.Parse(rdr["supplyidx"].ToString());

                if (rdr["name"] != DBNull.Value) retval.name = rdr["name"].ToString();
                if (rdr["unit"] != DBNull.Value) retval.unit = rdr["unit"].ToString();
                if (rdr["scale"] != DBNull.Value) retval.scale = float.Parse(rdr["scale"].ToString());
                if (rdr["price"] != DBNull.Value) retval.price = rdr["price"].ToString();
            }

            cn.Close();
            cn.Dispose();
            return retval;
        }
        public static Dictionary<string, string> getUserList(int baseLevel = 1)
        {
            string where = "isnull(level,0) >= " + baseLevel.ToString();
            return getTwoColumnList("vGroupUser", "id", "name", where, "name");

        }

        /// <summary>
        /// id,name,dispname,dept,email,level,tel,process,grade
        /// 활성화된 사용자목록을 반환 / 퇴사일자가 비어있어야 한다
        ///  id,name,dispname,dept,grade,email,level,tel,process,indate,outdate
        /// </summary>
        /// <param name="baseLevel"></param>
        /// <returns></returns>
        public static System.Data.DataTable getActiveUserTable(int baseLevel = 1)
        {
            var cn = getCn();
            cn.Open();

            var retval = new ItemModel();
            retval.idx = -1;

            string sql = "select [id],[name],([name] +'(' +[id] +')') as dispName,isnull([dept],'') as dept,isnull(grade,'') as grade," +
                $" [email],[level],[tel], isnull(processs, '') as process,isnull(indate, '') as indate, isnull(outdate, '') as outdate" +
                $" from vGroupUser " +
                $" where gcode='{FCOMMON.info.Login.gcode}' and isnull([level],0) >={baseLevel} and [id] <> 'dev' and isnull(outdate,'') = '' and useUserState = 1 " +
                $" order by[name]";

            var cmd = new SqlCommand(sql, cn);
            var da = new SqlDataAdapter(sql, cn);
            var ds = new System.Data.DataSet();
            da.Fill(ds);
            cn.Close();
            cn.Dispose();
            if (ds.Tables.Count > 0) return ds.Tables[0];
            else return null;
        }

        private static Dictionary<string, string> MakeDataTable(List<string> list)
        {
            var retval = new Dictionary<string, string>();
            foreach (var item in list)
                retval.Add(item, item);
            return retval;
        }
        private static System.Data.DataTable MakeDataTable(Dictionary<string, string> list)
        {
            System.Data.DataTable dt = new System.Data.DataTable();
            dt.Columns.Add("Key");
            dt.Columns.Add("Value");
            dt.Columns.Add("KeyValue");

            foreach (var item in list)
            {
                dt.Rows.Add(new string[] { item.Key, item.Value, string.Format("[{0}] {1}", item.Key, item.Value) });
            }
            dt.AcceptChanges();
            return dt;
        }

        public static Dictionary<string, string> getProjectList(string StateCode = "")
        {
            string where = "status = '{0}'";
            if (StateCode != "") where = string.Format(where, StateCode);
            else where = string.Empty;

            return getTwoColumnList("Projects", "idx", "name", where, "status,name");
        }
        public static System.Data.DataTable getProjectData(string StateCode = "")
        {
            var list = getProjectList(StateCode);
            return MakeDataTable(list);
        }
        public static Dictionary<string, string> getCodeList(string GroupCode = "99")
        {
            string where = "Grp = '{0}'";
            where = string.Format(where, GroupCode);
            return getTwoColumnList("Common", "code", "memo", where, "code");
        }
        public static string getCodeSvalue(string GroupCode, string code)
        {
            var cn = getCn();
            cn.Open();
            var sql = "select isnull(SValue,'')" +
                      " from Common  WITH (nolock) " +
                      " where gcode='" + FCOMMON.info.Login.gcode + "' and  Grp = '{0}' and code = '{1}'";

            sql = string.Format(sql, GroupCode, code);
            var cmd = new SqlCommand(sql, cn);
            var data = cmd.ExecuteScalar();
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            return data.ToString();
        }
        public static float getCodeFvalue(string GroupCode, string code)
        {
            var cn = getCn();
            cn.Open();
            var sql = "select isnull(FValue,0)" +
                      " from Common  WITH (nolock) " +
                      " where gcode='" + FCOMMON.info.Login.gcode + "' and  Grp = '{0}' and code = '{1}'";

            sql = string.Format(sql, GroupCode, code);
            var cmd = new SqlCommand(sql, cn);
            var data = cmd.ExecuteScalar();
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            return float.Parse(data.ToString());
        }

        public struct sCodeData
        {
            public string code;
            public string title;
            public string svalue;
            public string svalue2;
            public string grp;
        }
        public static sCodeData getCodeBySvalue(string GroupCode, string svalue)
        {
            var retval = new sCodeData();
            retval.code = string.Empty;
            retval.title = string.Empty;
            retval.svalue = string.Empty;
            retval.svalue2 = string.Empty;
            retval.grp = string.Empty;

            var cn = getCn();
            cn.Open();
            var sql = "select isnull(code,''),isnull(memo,''),isnull(svalue,''),isnull(svalue2,'')" +
                      " from Common  WITH (nolock) " +
                      " where gcode='" + FCOMMON.info.Login.gcode + "' and  Grp = '{0}' and svalue = '{1}'";

            sql = string.Format(sql, GroupCode, svalue);
            var cmd = new SqlCommand(sql, cn);
            var da = cmd.ExecuteReader();
            while (da.Read())
            {
                retval.code = da[0].ToString();
                retval.title = da[1].ToString();
                retval.svalue = da[2].ToString();
                retval.svalue2 = da[3].ToString();
            }

            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            retval.grp = GroupCode;
            return retval;
        }
        public static sCodeData getCodeByMemo(string GroupCode, string memo)
        {
            var retval = new sCodeData();
            retval.code = string.Empty;
            retval.title = string.Empty;
            retval.svalue = string.Empty;
            retval.svalue2 = string.Empty;
            retval.grp = string.Empty;


            var cn = getCn();
            cn.Open();
            var sql = "select isnull(code,''),isnull(memo,''),isnull(svalue,''),isnull(svalue2,'')" +
                      " from Common  WITH (nolock) " +
                      " where gcode='" + FCOMMON.info.Login.gcode + "' and  Grp = '{0}' and memo = '{1}'";

            sql = string.Format(sql, GroupCode, memo);
            var cmd = new SqlCommand(sql, cn);
            var da = cmd.ExecuteReader();
            while (da.Read())
            {
                retval.code = da[0].ToString();
                retval.title = da[1].ToString();
                retval.svalue = da[2].ToString();
                retval.svalue2 = da[3].ToString();
            }

            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            retval.grp = GroupCode;
            //retval.svalue = memo;
            return retval;
        }

        public static Boolean InsertLog(string cate, string remark, string pdate = "")
        {
            if (String.IsNullOrEmpty(pdate)) pdate = DateTime.Now.ToString("yyyy-MM-dd");

            try
            {
                var cn = getCn();
                cn.Open();
                var sql = "insert into EETGW_Log(gcode,pdate,cate,remark,wuid,wdate)" +
                         " values(@gcode,@pdate,@cate,@remark,@wuid,@wdate)";

                //sql = string.Format(sql, info.Login.gcode, memo);
                var cmd = new SqlCommand(sql, cn);
                cmd.Parameters.Add(new SqlParameter("gcode", FCOMMON.info.Login.gcode));
                cmd.Parameters.Add(new SqlParameter("pdate", pdate));
                cmd.Parameters.Add(new SqlParameter("cate", cate));
                cmd.Parameters.Add(new SqlParameter("remark", remark));
                cmd.Parameters.Add(new SqlParameter("wuid", FCOMMON.info.Login.no));
                cmd.Parameters.Add(new SqlParameter("wdate", DateTime.Now));
                var da = cmd.ExecuteNonQuery();

                cmd.Dispose();
                cn.Close();
                cn.Dispose();
                return da > 0;
            }

            catch { }
            return false;
        }


        //public static Boolean insertCommonCode(string GroupCode, string code, string memo, string svalue = "",string svalue)
        //{

        //    var cn = getCn();
        //    cn.Open();
        //    var sql = "insert into common(gcode,grp,code,svalue,memo,wuid,wdate)" +
        //             " values(@gcode,@grp,@code,@svalue,@memo,@wuid,@wdate)";

        //    sql = string.Format(sql, GroupCode, memo);
        //    var cmd = new SqlCommand(sql, cn);
        //    cmd.Parameters.Add(new SqlParameter("gcode", FCOMMON.info.Login.gcode));
        //    cmd.Parameters.Add(new SqlParameter("grp", GroupCode));
        //    cmd.Parameters.Add(new SqlParameter("code", code));
        //    cmd.Parameters.Add(new SqlParameter("memo", memo));
        //    cmd.Parameters.Add(new SqlParameter("svalue", svalue));
        //    cmd.Parameters.Add(new SqlParameter("wuid", FCOMMON.info.Login.no));
        //    cmd.Parameters.Add(new SqlParameter("wdate", DateTime.Now));
        //    var da = cmd.ExecuteNonQuery();

        //    cmd.Dispose();
        //    cn.Close();
        //    cn.Dispose();
        //    return da > 0;
        //}

        public static sCodeData getCodeByCode(string GroupCode, string code)
        {
            var retval = new sCodeData();
            retval.code = string.Empty;
            retval.title = string.Empty;
            retval.svalue = string.Empty;
            retval.svalue2 = string.Empty;
            retval.grp = string.Empty;

            var cn = getCn();
            cn.Open();
            var sql = "select isnull(code,''),isnull(memo,''),isnull(svalue,''),isnull(svalue2,'')" +
                      " from Common  WITH (nolock) " +
                      " where gcode='" + FCOMMON.info.Login.gcode + "' and  Grp = '{0}' and code = '{1}'";

            sql = string.Format(sql, GroupCode, code);
            var cmd = new SqlCommand(sql, cn);
            var da = cmd.ExecuteReader();
            while (da.Read())
            {
                retval.code = da[0].ToString();
                retval.title = da[1].ToString();
                retval.svalue = da[2].ToString();
                retval.svalue2 = da[3].ToString();
            }

            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            retval.grp = GroupCode;
            //retval.svalue = code;
            return retval;
        }

        /// <summary>
        /// 지정된 프로젝트의 마지막 업무일지 데이터를 반환함 
        /// </summary>
        /// <param name="projectIdx"></param>
        /// <returns></returns>
        public static System.Data.DataTable getLastJobReportData(string uid, int projectIdx)
        {
            var cn = getCn();
            cn.Open();
            var sql = "select top 1 * from JobReport  WITH (nolock) " +
                " where gcode ='" + FCOMMON.info.Login.gcode + "' and  isnull(pidx,-1)=" + projectIdx.ToString() +
                " and uid ='" + uid + "'" +
                " order by pdate desc, idx desc";
            var da = new SqlDataAdapter(sql, cn);
            var ds = new System.Data.DataSet();
            da.Fill(ds);
            cn.Close();
            if (ds.Tables.Count > 0) return ds.Tables[0];
            else return null;
        }
        public static System.Data.DataTable getLastJobReportDatabyProjectName(string uid, string prjName)
        {
            var cn = getCn();
            cn.Open();
            var sql = "select top 1 * from JobReport  WITH (nolock) " +
                " where gcode='" + FCOMMON.info.Login.gcode + "' and isnull(projectName,'') like '" + prjName + "'" +
                " and uid ='" + uid + "'" +
                " order by pdate desc, idx desc";
            var da = new SqlDataAdapter(sql, cn);
            var ds = new System.Data.DataSet();
            da.Fill(ds);
            cn.Close();
            if (ds.Tables.Count > 0) return ds.Tables[0];
            else return null;
        }
        public static System.Data.DataTable getLastJobReportData(string uid, string type)
        {
            var cn = getCn();
            cn.Open();
            var sql = "select top 1 * from JobReport WITH (nolock) " +
                " where gcode = '" + FCOMMON.info.Login.gcode + "' and  isnull([type],'')='" + type + "'" +
                " and uid ='" + uid + "'" +
                " order by pdate desc, idx desc";
            var da = new SqlDataAdapter(sql, cn);
            var ds = new System.Data.DataSet();
            da.Fill(ds);
            cn.Close();
            if (ds.Tables.Count > 0) return ds.Tables[0];
            else return null;
        }

        public static System.Data.DataTable getProcessList()
        {

            System.Data.DataTable retval = new System.Data.DataTable();
            retval.Columns.Add("Code");
            retval.Columns.Add("Value");

            var cn = getCn();
            cn.Open();
            var sql = "select isnull(processs,'') as process" +
                        " from Users  WITH (nolock) " +
                        " where processs is not null and gcode='{0}'" +
                        " group by processs" +
                        " order by process";

            sql = string.Format(sql, FCOMMON.info.Login.gcode);
            var cmd = new SqlCommand(sql, cn);
            var rdr = cmd.ExecuteReader();
            var cnt = 0;
            while (rdr.Read())
            {
                retval.Rows.Add(new string[] { cnt.ToString(), rdr[0].ToString() });
                cnt += 1;
            }
            rdr.Close();
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            return retval;
        }
        public static string GetUserName(string gcode, string uid)
        {
            var slq = "select isnull(name,'') from vGroupUser" +
                    $" where gcode = '{gcode}'" +
                    $" and id = '{uid}'";
            try
            {
                return ExecuteScalar(slq);
            }
            catch
            {
                return string.Empty;
            }

        }
        public static string GetUserTel(string gcode, string uid)
        {
            var slq = "select isnull(tel,'') from vGroupUser" +
                    $" where gcode = '{gcode}'" +
                    $" and id = '{uid}'";
            try
            {
                return ExecuteScalar(slq);
            }
            catch
            {
                return string.Empty;
            }

        }

        public static System.Data.DataTable getUserProjectList(string userName)
        {

            System.Data.DataTable retval = new System.Data.DataTable();
            retval.Columns.Add("Code");
            retval.Columns.Add("Value");
            retval.Columns.Add("NameOnly");

            var cn = getCn();
            cn.Open();
            var sql = "select idx, '[' + cast(idx as varchar) + '] ' + isnull(name,''),isnull(name,'')  from Projects  WITH (nolock) " +
                " where gcode='{0}'" +
                " and  (isnull(userManager,'') like '%{1}%'" +
                " or  isnull(userMain,'') like '%{1}%'" +
                " or  isnull(usersub,'') like '%{1}%')" +
                " and status not in ('보류', '취소', '완료(보고)')" +
                " order by status desc,pdate desc,name";
            //" order by pdate desc,name";
            sql = string.Format(sql, FCOMMON.info.Login.gcode, userName);
            var cmd = new SqlCommand(sql, cn);
            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                retval.Rows.Add(new string[] {
                    rdr[0].ToString(),
                    rdr[1].ToString(),
                    rdr[2].ToString()
                });
            }
            rdr.Close();
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            return retval;
        }


        public static System.Data.DataTable getCodeTable(string GroupCode = "99", string sort = "memo")
        {

            System.Data.DataTable retval = new System.Data.DataTable();
            retval.Columns.Add("Code", typeof(string));
            retval.Columns.Add("Value", typeof(string));
            retval.Columns.Add("SValue", typeof(string));
            retval.Columns.Add("FValue", typeof(float));
            retval.Columns.Add("SValue2", typeof(string));

            var cn = getCn();
            cn.Open();
            var sql = "select isnull(code,''),isnull(memo ,''),isnull(svalue,''),isnull(fvalue,0),isnull(svalue2,'')" +
                " from common  WITH (nolock) " +
                " where gcode='" + FCOMMON.info.Login.gcode + "' and grp = '" + GroupCode + "'" +
                " and isnull(code,'') <> ''" +
                " order by ";

            var sortidx = 0;
            var sortlist = sort.Split(',');
            foreach (var sortstr in sortlist)
            {
                if (string.IsNullOrEmpty(sortstr)) continue;
                if (sortidx > 0) sql += ",";
                sql += "isnull(" + sortstr + ",'')";
                sortidx += 1;
            }

            var cmd = new SqlCommand(sql, cn);
            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                retval.Rows.Add(new string[] { rdr[0].ToString(), rdr[1].ToString(), rdr[2].ToString(), rdr[3].ToString(), rdr[4].ToString() });
            }
            rdr.Close();
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            return retval;
        }
        public static Dictionary<string, string> getTwoColumnList(string table, string col1, string col2, string where = "", string order = "")
        {
            Dictionary<string, string> retval = new Dictionary<string, string>();
            var cn = getCn();
            cn.Open();
            var sql = "select isnull({1},''),isnull({2},'')" +
                " from {0}  WITH (nolock) " +
                " where gcode = '" + FCOMMON.info.Login.gcode + "' ";
            if (where != "") sql += " and " + where;
            if (order != "") sql += " order by " + order;
            sql = string.Format(sql, table, col1, col2);
            var cmd = new SqlCommand(sql, cn);
            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                retval.Add(rdr[0].ToString(), rdr[1].ToString());
            }
            rdr.Close();
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            return retval;
        }
        public static List<string> getPlaceList(string gcode)
        {
            var retval = new List<string>();
            var cn = getCn();
            cn.Open();
            var sql = "select isnull(place,'')" +
                " from Inventory  WITH (nolock) " +
                " where gcode = '{0}' and isnull(place,'') <> ''" +
                " group by place order by place";
            sql = string.Format(sql, gcode);
            var cmd = new SqlCommand(sql, cn);
            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                retval.Add(rdr[0].ToString());
            }
            rdr.Close();
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            return retval;
        }
        public static Dictionary<string, string> getGroupTable(string GroupColumn, string table, string where = "", Boolean desc = false)
        {
            var list = getGroupList(GroupColumn, table, where, desc);
            return MakeDataTable(list);
        }

        /// <summary>
        /// 데이터중 첫번째 자료를 반환 합니다.
        /// </summary>
        /// <param name="column"></param>
        /// <param name="table"></param>
        /// <param name="where"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        public static String getFirstValue(string column, string table, string where = "", string order = "")
        {
            string retval = string.Empty;
            var cn = getCn();
            cn.Open();
            var sql = "select {0} " +
                " from {1}  WITH (nolock) " +
                " where gcode='" + FCOMMON.info.Login.gcode + "' and isnull({0},'') != '' ";

            if (where != "") sql += " and " + where;
            if (order != "") sql += " order by " + order;

            sql = string.Format(sql, "[" + column + "]", table);
            var cmd = new SqlCommand(sql, cn);
            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                if (rdr[0] != null) retval = rdr[0].ToString();
            }
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            return retval;
        }


        /// <summary>
        /// 지정된 사용자/월의 전체 근무시간 초과시간을 반환함
        /// </summary>
        /// <param name="uid">사용자번호</param>
        /// <param name="yymm">지정월(2019-05)</param>
        /// <param name="work">근무시간</param>
        /// <param name="total">최대근무시간(근무일수*8)</param>
        /// <param name="ot">초과근무시간</param>
        public static void getWorkTime(string uid, string yymm, out float work, out int total, out float ot)
        {
            work = 0;
            total = 0;
            ot = 0;
            string retval = string.Empty;
            var cn = getCn();

            try
            {

                cn.Open();
                var sql = "select isnull(sum(hrs),0) as hrs,isnull(sum(ot),0) as ot,dbo.getWorkDayCount('{1}') as workday" +
                    " from JobReport  WITH (nolock) " +
                    " where gcode='" + FCOMMON.info.Login.gcode + "' and uid = '{0}' and substring(pdate,1,7) = '{1}'";

                sql = string.Format(sql, uid, yymm);
                var cmd = new SqlCommand(sql, cn);
                var rdr = cmd.ExecuteReader();
                while (rdr.Read())
                {
                    work = float.Parse(rdr[0].ToString());
                    ot = float.Parse(rdr[1].ToString());
                    total = int.Parse(rdr[2].ToString()) * 8;
                }
                cmd.Dispose();
                cn.Close();
                cn.Dispose();
            }
            catch
            {
                work = 0;
                total = 0;
                ot = 0;
            }
            finally
            {
                if (cn != null) cn.Dispose();
            }
        }

        public static string GetcurrentUserNoName()
        {
            var currentusername = $"[{FCOMMON.info.Login.no}] {FCOMMON.info.Login.nameK}";
            return currentusername;
        }

        public static bool GetUserGroupUseNR()
        {
            var cn = getCn();
            cn.Open();

            int retval = 0;
            var cmd2 = new SqlCommand($"select isnull(usenr,1)  from UserGroup where gcode = '{FCOMMON.info.Login.gcode}'", cn);
            try
            {
                var value = cmd2.ExecuteScalar();
                retval = value.ToString().ToLower() == "true" ? 1 : 0;
                //if (int.TryParse(value.ToString(), out retval))
                //{

                //}
                //else retval = 0;

            }
            catch (Exception ex)
            {

            }
            return retval > 0;
        }
        public static bool SetUserGroupUseNR(bool a)
        {
            var cn = getCn();
            cn.Open();

            var value = a ? 1 : 0;
            int retval = 0;
            var cmd2 = new SqlCommand($"update UserGroup set usenr = {value}  where gcode = '{FCOMMON.info.Login.gcode}'", cn);
            try
            {
                retval = cmd2.ExecuteNonQuery();

            }
            catch(Exception ex)
            {

            }
            return retval == 1;
        }

        public static int addItem(string pumname, string sid, string model, decimal price, string supply, int supplyidx = -1, byte[] pic = null)
        {

            var cn = getCn();
            cn.Open();

            int retval = -1;
            var cmd2 = new SqlCommand("", cn);

            cmd2.CommandText = string.Format("select count(*) from Items  WITH (nolock) " +
                " where  ISNULL(REPLACE(name, ' ', '') + REPLACE(model, ' ', ''), '') = '{0}'", pumname.Replace(" ", "").Replace("'", "''") + model.Replace(" ", "").Replace("'", "''"));
            var cnt = int.Parse(cmd2.ExecuteScalar().ToString());
            if (cnt == 0)
            {
                DateTime wdate = DateTime.Now;

                if (pic == null)
                {
                    cmd2.CommandText = "insert into items(gcode,cate,name,sid,model,scale,unit,supply,supplyidx,price,wuid,wdate)" +
                       "values(@gcode,@cate,@name,@sid,@model,@scale,@unit,@supply,@supplyidx,@price,@wuid,@wdate)";
                }
                else
                {
                    cmd2.CommandText = "insert into items(gcode,cate,name,sid,model,scale,unit,supply,supplyidx,price,image,wuid,wdate)" +
                       "values(@gcode,@cate,@name,@sid,@model,@scale,@unit,@supply,@supplyidx,@price,@image,@wuid,@wdate)";
                }

                cmd2.Parameters.Clear();
                cmd2.Parameters.Add(new SqlParameter("gcode", FCOMMON.info.Login.gcode));
                cmd2.Parameters.Add(new SqlParameter("cate", "--"));
                cmd2.Parameters.Add(new SqlParameter("name", pumname.Trim()));
                cmd2.Parameters.Add(new SqlParameter("sid", sid.Trim()));
                cmd2.Parameters.Add(new SqlParameter("model", model.Trim()));
                cmd2.Parameters.Add(new SqlParameter("scale", 1.0));
                cmd2.Parameters.Add(new SqlParameter("unit", "EA"));
                cmd2.Parameters.Add(new SqlParameter("supply", supply));
                if (pic != null) cmd2.Parameters.Add(new SqlParameter("image", pic));
                cmd2.Parameters.Add(new SqlParameter("supplyidx", supplyidx));
                cmd2.Parameters.Add(new SqlParameter("price", price));
                cmd2.Parameters.Add(new SqlParameter("wuid", FCOMMON.info.Login.no));
                cmd2.Parameters.Add(new SqlParameter("wdate", wdate));
                retval += cmd2.ExecuteNonQuery();

                //추가된 데이터를 찾아서 다시 검색한다.
                //if (retval == 0)
                //{
                //    cmd2.CommandText = "select idx from Items where gcode=@gcode and  name = @name and sid = @sid and model = @model and wuid = @wuid and wdate = @wdate";
                //    retval = int.Parse(cmd2.ExecuteScalar().ToString());
                //}
                //else retval = -1;
            }

            //{
            cmd2.CommandText = string.Format("select min(idx) from Items  WITH (nolock) where gcode='" + FCOMMON.info.Login.gcode + "' and  ISNULL(REPLACE(name, ' ', '') + REPLACE(model, ' ', ''), '') = '{0}'", pumname.Replace(" ", "").Replace("'", "''") + model.Replace(" ", "").Replace("'", "''"));
            var itemdata = cmd2.ExecuteScalar();
            if (itemdata == DBNull.Value || itemdata == null)
            {
                retval = -1;
            }
            else
            {
                var strItem = itemdata.ToString();
                if (strItem == "") retval = -1;
                else retval = int.Parse(strItem);
            }

            //}
            cmd2.Dispose();
            cn.Close();
            cn.Dispose();
            return retval;
        }

        public static Boolean UpdateItemSID(int itemIdx, string sid)
        {
            var cn = getCn();
            cn.Open();

            int retval = 0;
            var cmd2 = new SqlCommand("", cn);

            cmd2.CommandText = string.Format("update Items  WITH (nolock) set sid=@sid where idx=@idx");

            cmd2.Parameters.Clear();
            cmd2.Parameters.Add(new SqlParameter("idx", itemIdx));
            cmd2.Parameters.Add(new SqlParameter("sid", sid));
            retval = cmd2.ExecuteNonQuery();
            cmd2.Dispose();
            cn.Close();
            cn.Dispose();
            return retval != 0;
        }
        public static List<String> getGroupListWithoutGcode(string GroupColumn, string table, string where = "", Boolean desc = false, Boolean useColumncover = true)
        {
            List<string> retval = new List<string>();
            var cn = getCn();
            cn.Open();
            var sql = "select {0} " +
                " from {1}  WITH (nolock) " +
                " where isnull({0},'') != '' ";

            if (table.ToUpper() == "USERS")
                sql = "select {0} " +
                " from {1}  WITH (nolock) " +
                " where isnull({0},'') != '' ";


            if (where != "") sql += " and " + where;

            sql += " group by {0} " +
                   " order by {0} ";
            if (desc) sql += " desc";

            if (useColumncover)
                sql = string.Format(sql, "[" + GroupColumn + "]", table);
            else
                sql = string.Format(sql, GroupColumn, table);
            var cmd = new SqlCommand(sql, cn);
            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                retval.Add(rdr[0].ToString());
            }
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            return retval;
        }
        public static List<String> getGroupList(string GroupColumn, string table, string where = "", Boolean desc = false, Boolean useColumncover = true)
        {
            List<string> retval = new List<string>();
            var cn = getCn();
            cn.Open();
            var sql = "select {0} " +
                " from {1}  WITH (nolock) " +
                " where gcode='" + FCOMMON.info.Login.gcode + "' and isnull({0},'') != '' ";

            if (table.ToUpper() == "USERS")
                sql = "select {0} " +
                " from {1}   WITH (nolock) " +
                " where isnull({0},'') != '' ";


            if (where != "") sql += " and " + where;

            sql += " group by {0} " +
                   " order by {0} ";
            if (desc) sql += " desc";

            if (useColumncover)
                sql = string.Format(sql, "[" + GroupColumn + "]", table);
            else
                sql = string.Format(sql, GroupColumn, table);
            var cmd = new SqlCommand(sql, cn);
            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                retval.Add(rdr[0].ToString());
            }
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            return retval;
        }

        public static String getPathKJ(string dept)
        {
            var cn = getCn();
            cn.Open();
            var sql = "select max(isnull(path_kj,'')) " +
                " from UserGroup  WITH (nolock)  " +
                " where dept = '" + dept + "'";

            sql = string.Format(sql);
            var cmd = new SqlCommand(sql, cn);
            var rdr = cmd.ExecuteScalar();
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            if (rdr == null) return string.Empty;
            else return rdr.ToString();
        }
        public static Boolean setPathKJ(string dept, string path)
        {
            var cn = getCn();
            cn.Open();
            var sql = "update UserGroup set path_kj=@path" +
                " where dept = @dept";

            sql = string.Format(sql);
            var cmd = new SqlCommand(sql, cn);
            cmd.Parameters.Add(new SqlParameter("path", path));
            cmd.Parameters.Add(new SqlParameter("dept", dept));
            var rdr = cmd.ExecuteNonQuery();
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            return rdr > 0;
        }

        public static List<String> getDateList(string table, string where = "", Boolean desc = false)
        {
            return getGroupList("pdate", table, where, desc);
        }

        public static int UpdateItemIndexbySID()
        {
            int retval = 0;
            var cn1 = getCn();
            cn1.Open();

            var cn2 = getCn();
            cn2.Open();

            var sql = "select idx, " +
                        " isnull(pumname,'') as pumname, " +
                        " isnull([sid],'') as [sid], " +
                        " isnull(pumscale,'') as pummodel, " +
                        " isnull(pumunit,'EA') as pumunit, " +
                        " isnull(pumprice,0) as pumprice, " +
                        " isnull(supply,'') as supply, " +
                        " isnull(supplyidx,-1) as supplyidx" +
                        " from purchase  WITH (nolock) " +
                        " where  gcode='" + FCOMMON.info.Login.gcode + "' and  isnull(sid,'') <> '' and " +
                        " isnull(sid,'') <> '신규'" +
                        " and isnull(pumidx,-1) = -1 " +
                        " and len(sid) = 9" +
                        " and isnull(pumname,'') <> ''";

            var cmd2 = new SqlCommand("", cn2);
            var cmd = new SqlCommand(sql, cn1);
            var rdr = cmd.ExecuteReader();
            while (rdr.Read())
            {
                var pumname = rdr["pumname"].ToString();
                var pummodel = rdr["pummodel"].ToString();
                var pumunit = rdr["pumunit"].ToString();
                var pumprice = decimal.Parse(rdr["pumprice"].ToString());
                var supply = rdr["supply"].ToString();
                var supplyidx = int.Parse(rdr["supplyidx"].ToString());

                var sid = rdr["sid"].ToString();
                var idx = int.Parse(rdr["idx"].ToString());

                //아이템정보에서 이 sid 가 1개 존재한다면 그것에 연결한다.
                var sql2 = "select isnull(idx,-1) from Items where gcode='" + FCOMMON.info.Login.gcode + "' and [sid] = '" + sid + "'";
                cmd2.CommandText = sql2;

                var itemdata = cmd2.ExecuteScalar();
                if (itemdata != null && itemdata.ToString() != "-1")
                {
                    cmd2.CommandText = "update purchase set pumidx = " + itemdata.ToString() +
                        " where gcode='" + FCOMMON.info.Login.gcode + "' and idx=" + idx.ToString();
                    retval += cmd2.ExecuteNonQuery();
                }
                else
                {
                    cmd2.CommandText = "insert into items(gcode,cate,name,sid,model,scale,unit,supply,supplyidx,price,wuid,wdate)" +
                        "values(@gcode,@cate,@name,@sid,@model,@scale,@unit,@supply,@supplyidx,@price,@wuid,@wdate)";
                    cmd2.Parameters.Clear();
                    cmd2.Parameters.Add(new SqlParameter("gcode", FCOMMON.info.Login.gcode));
                    cmd2.Parameters.Add(new SqlParameter("cate", "--"));
                    cmd2.Parameters.Add(new SqlParameter("name", pumname));
                    cmd2.Parameters.Add(new SqlParameter("sid", sid));
                    cmd2.Parameters.Add(new SqlParameter("model", pummodel));
                    cmd2.Parameters.Add(new SqlParameter("scale", 1.0));
                    cmd2.Parameters.Add(new SqlParameter("unit", pumunit));
                    cmd2.Parameters.Add(new SqlParameter("supply", supply));
                    cmd2.Parameters.Add(new SqlParameter("supplyidx", supplyidx));
                    cmd2.Parameters.Add(new SqlParameter("price", pumprice));
                    cmd2.Parameters.Add(new SqlParameter("wuid", "dev"));
                    cmd2.Parameters.Add(new SqlParameter("wdate", DateTime.Now));
                    retval += cmd2.ExecuteNonQuery();
                }


            }
            cmd2.Dispose();
            cmd.Dispose();
            cn1.Close();
            cn1.Dispose();

            cn2.Close();
            cn2.Dispose();
            return retval;
        }

        #region Generic Query Methods

        /// <summary>
        /// Generic Query method that returns a list of objects of type T
        /// </summary>
        /// <typeparam name="T">The type to map the results to</typeparam>
        /// <param name="sql">SQL query string</param>
        /// <param name="parameters">Anonymous object containing parameters</param>
        /// <returns>List of objects of type T</returns>
        public static List<T> Query<T>(string sql, object parameters = null) where T : new()
        {
            var retval = new List<T>();
            var cn = getCn();

            try
            {
                cn.Open();
                var cmd = new SqlCommand(sql, cn);

                // Add parameters if provided
                if (parameters != null)
                {
                    AddParameters(cmd, parameters);
                }

                var rdr = cmd.ExecuteReader();
                while (rdr.Read())
                {
                    var item = MapReaderToObject<T>(rdr);
                    retval.Add(item);
                }
                rdr.Close();
                cmd.Dispose();
            }
            catch (Exception ex)
            {
                // Log error if needed
                throw new Exception($"Query<{typeof(T).Name}> failed: {ex.Message}", ex);
            }
            finally
            {
                cn.Close();
                cn.Dispose();
            }

            return retval;
        }

        /// <summary>
        /// Generic QuerySingle method that returns a single object of type T
        /// </summary>
        /// <typeparam name="T">The type to map the result to</typeparam>
        /// <param name="sql">SQL query string</param>
        /// <param name="parameters">Anonymous object containing parameters</param>
        /// <returns>Single object of type T</returns>
        /// <exception cref="InvalidOperationException">Thrown when no data is found or more than one row is returned</exception>
        public static T QuerySingle<T>(string sql, object parameters = null) where T : new()
        {
            var results = Query<T>(sql, parameters);

            if (results.Count == 0)
                throw new InvalidOperationException("Sequence contains no elements");
            if (results.Count > 1)
                throw new InvalidOperationException("Sequence contains more than one element");

            return results.First();
        }

        /// <summary>
        /// Generic QuerySingleOrDefault method that returns a single object of type T or default value
        /// </summary>
        /// <typeparam name="T">The type to map the result to</typeparam>
        /// <param name="sql">SQL query string</param>
        /// <param name="parameters">Anonymous object containing parameters</param>
        /// <returns>Single object of type T or default value if no data found</returns>
        /// <exception cref="InvalidOperationException">Thrown when more than one row is returned</exception>
        public static T QuerySingleOrDefault<T>(string sql, object parameters = null) where T : new()
        {
            var results = Query<T>(sql, parameters);

            if (results.Count == 0)
                return default(T);
            if (results.Count > 1)
                throw new InvalidOperationException("Sequence contains more than one element");

            return results.First();
        }

        /// <summary>
        /// Execute a command with parameters and return the number of affected rows
        /// </summary>
        /// <param name="sql">SQL command string</param>
        /// <param name="parameters">Anonymous object containing parameters</param>
        /// <returns>Number of affected rows</returns>
        public static int Execute(string sql, object parameters = null)
        {
            var cn = getCn();
            int retval = 0;

            try
            {
                cn.Open();
                var cmd = new SqlCommand(sql, cn);

                // Add parameters if provided
                if (parameters != null)
                {
                    AddParameters(cmd, parameters);
                }

                retval = cmd.ExecuteNonQuery();
                cmd.Dispose();
            }
            catch (Exception ex)
            {
                throw new Exception($"Execute failed: {ex.Message}", ex);
            }
            finally
            {
                cn.Close();
                cn.Dispose();
            }

            return retval;
        }

        /// <summary>
        /// Helper method to add parameters from an anonymous object to a SqlCommand
        /// </summary>
        /// <param name="cmd">SqlCommand to add parameters to</param>
        /// <param name="parameters">Anonymous object containing parameters</param>
        private static void AddParameters(SqlCommand cmd, object parameters)
        {
            if (parameters == null) return;

            var properties = parameters.GetType().GetProperties();
            foreach (var prop in properties)
            {
                var value = prop.GetValue(parameters, null) ?? DBNull.Value;
                cmd.Parameters.AddWithValue("@" + prop.Name, value);
            }
        }

        /// <summary>
        /// Helper method to map a SqlDataReader to an object of type T
        /// </summary>
        /// <typeparam name="T">The type to map to</typeparam>
        /// <param name="reader">SqlDataReader containing the data</param>
        /// <returns>Object of type T with mapped values</returns>
        private static T MapReaderToObject<T>(SqlDataReader reader) where T : new()
        {
            var obj = new T();
            var type = typeof(T);
            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (var prop in properties)
            {
                // Check if the property has a setter
                if (!prop.CanWrite) continue;

                // Try to find a column with the same name (case insensitive)
                var columnName = FindColumnName(reader, prop.Name);
                if (columnName == null) continue;

                var value = reader[columnName];
                if (value == DBNull.Value) continue;

                // Convert the value to the property type if needed
                try
                {
                    if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    {
                        // Handle nullable types
                        var underlyingType = Nullable.GetUnderlyingType(prop.PropertyType);
                        var convertedValue = Convert.ChangeType(value, underlyingType);
                        prop.SetValue(obj, convertedValue, null);
                    }
                    else
                    {
                        var convertedValue = Convert.ChangeType(value, prop.PropertyType);
                        prop.SetValue(obj, convertedValue, null);
                    }
                }
                catch
                {
                    // If conversion fails, skip this property
                }
            }

            return obj;
        }

        /// <summary>
        /// Helper method to find a column name in the reader (case insensitive)
        /// </summary>
        /// <param name="reader">SqlDataReader to search in</param>
        /// <param name="propertyName">Property name to find</param>
        /// <returns>Column name if found, null otherwise</returns>
        private static string FindColumnName(SqlDataReader reader, string propertyName)
        {
            for (int i = 0; i < reader.FieldCount; i++)
            {
                var columnName = reader.GetName(i);
                if (string.Equals(columnName, propertyName, StringComparison.OrdinalIgnoreCase))
                {
                    return columnName;
                }
            }
            return null;
        }

        #endregion
    }
}
