using System;
using System.Collections.Generic;
using System.Drawing;
using System.Net;
using System.IO;
using System.Web;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Xml;
using System.Windows.Forms;
using System.Reflection;
using Excel = Microsoft.Office.Interop.Excel;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using UniMarc.BaroService_API;
using UniMarc.BaroService_TI;
using System.Text.RegularExpressions;
using System.Drawing.Printing;
using System.ComponentModel;
using System.Drawing.Text;
using System.Globalization;
using System.Threading;
using System.Data.SqlTypes;
using AR;
using System.Runtime.InteropServices.WindowsRuntime;

namespace UniMarc
{
    /// <summary>
    /// 여러 기능들이 추가될 예정.
    /// Excel_to_DataGridView
    /// </summary>
    class Skill_Grid
    {

        /// <summary>
        /// 숫자형 정렬이 필요할때 쓰는 함수.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <param name="ColumnName"></param>
        public void dataGridView_SortCompare(object sender, DataGridViewSortCompareEventArgs e, string ColumnName)
        {
            if (e.Column.Name.Equals(ColumnName))
            {
                int a = int.Parse(e.CellValue1.ToString());
                int b = int.Parse(e.CellValue2.ToString());
                e.SortResult = a.CompareTo(b);
                e.Handled = true;
            }
        }

        /// <summary>
        /// Grid 정렬 CellClick => if (e.RowIndex < 0) 안에 들어가야함.
        /// </summary>
        /// <param name="dataGridView">사용할 데이터 그리드 뷰</param>
        /// <param name="col">클릭시 나오는 e.ColumnIndex</param>
        public void Grid_Sort(DataGridView dataGridView, int col)
        {
            if (System.ComponentModel.ListSortDirection.Ascending == 0)
                dataGridView.Sort(dataGridView.Columns[col], System.ComponentModel.ListSortDirection.Descending);

            else
                dataGridView.Sort(dataGridView.Columns[col], System.ComponentModel.ListSortDirection.Ascending);


        }
        /// <summary>
        /// * Row헤더에 체크박스를 넣는 기능*
        /// *설정오류* 복사해서 사용할것.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <param name="colCount">체크박스를 넣을 컬럼 위치</param>
        public void Add_Row_CheckBox(DataGridView sender, DataGridViewCellPaintingEventArgs e, int colCount)
        {
            if (e.ColumnIndex == colCount && e.RowIndex == -1)
            {
                e.PaintBackground(e.ClipBounds, false);

                Point pt = e.CellBounds.Location;

                int nChkBoxWidth = 15;
                int nChkBoxHeight = 15;
                int offsetX = (e.CellBounds.Width - nChkBoxWidth) / 2;
                int offsetY = (e.CellBounds.Height - nChkBoxHeight) / 2;

                pt.X += offsetX;
                pt.Y += offsetY;

                CheckBox cb = new CheckBox();
                cb.Size = new Size(nChkBoxWidth, nChkBoxHeight);
                cb.Location = pt;
                cb.CheckedChanged += new EventHandler(datagridview_checkBox_Click);
                sender.Controls.Add(cb);

                e.Handled = true;
            }
        }
        private void datagridview_checkBox_Click(object sender, EventArgs e)
        {
            foreach (DataGridViewRow r in ((DataGridView)sender).Rows)
            {
                r.Cells["colCheck"].Value = ((CheckBox)sender).Checked;
            }
        }
        /// <summary>
        /// 엑셀에서 복사한 데이터를 DataGirdView에 붙여넣어주는 코드 (단, KeyDown에 넣어야함!!!!)
        /// </summary>
        /// <param name="sender">KeyDown의 object "sender"</param>
        /// <param name="e">KeyDown의 KeyEventArgs "e"</param>
        public void Excel_to_DataGridView(object sender, KeyEventArgs e)
        {
            //if user clicked Shift+Ins or Ctrl+V (paste from clipboard)
            if ((e.Shift && e.KeyCode == Keys.Insert) || (e.Control && e.KeyCode == Keys.V))
            {
                char[] rowSplitter = { '\r', '\n' };
                string[] rowSpliteter = { "\r\n" };
                char[] columnSplitter = { '\t' };

                //get the text from clipboard

                if (Clipboard.ContainsText() == false) return;

                string stringInClipboard = null;

                if (e.Alt)
                    stringInClipboard = Clipboard.GetText(TextDataFormat.UnicodeText);
                else
                    stringInClipboard = Clipboard.GetText();//  (string)objdata;

                //split it into lines
                //20230209 \r텝 기능과 \n 줄넘김 기능을 같이 공백 제거 처리해버려 공백칸을 활용해야 함에도 제거하는 현상 발생.
                //텝 공백 문자열 동시에 사용하여 분류
                // stringInClipboard= stringInClipboard.Replace("\r", "");
                if (stringInClipboard == null) return;
                List<string> rowsInClipboard = stringInClipboard.Split(rowSpliteter, StringSplitOptions.None).ToList();
                if (rowsInClipboard.Last().isEmpty()) rowsInClipboard.RemoveAt(rowsInClipboard.Count - 1);

                var dv = sender as DataGridView;

                int r = dv.SelectedCells[0].RowIndex;
                int c = dv.SelectedCells[0].ColumnIndex;
                //add rows into dataGridView1 to fit clipboard lines
                if (dv.Rows.Count < (r + rowsInClipboard.Count))
                {
                    dv.Rows.Add(r + rowsInClipboard.Count - dv.Rows.Count);
                }
                // loop through the lines, split them into cells and place the values in the corresponding cell.
                for (int iRow = 0; iRow < rowsInClipboard.Count; iRow++)
                {
                    //split row into cell values
                    string[] valuesInRow = rowsInClipboard[iRow].Split(columnSplitter);
                    //cycle through cell values
                    for (int iCol = 0; iCol < valuesInRow.Length; iCol++)
                    {
                        //assign cell value, only if it within columns of the dataGridView1
                        if (dv.ColumnCount - 1 >= c + iCol)
                        {
                            if (dv.Rows.Count <= r + iRow) continue;
                            dv.Rows[r + iRow].Cells[c + iCol].Value = valuesInRow[iCol];
                        }
                    }
                }
            }
        }
        /// <summary>
        /// DataGirdView의 활성화된 셀값을 삭제하는 코드 (단, KeyDown에 넣어야함!!!!)
        /// 사전에 if(e.KeyCode == Keys.Delete)안에 들어가야함.
        /// </summary>
        /// <param name="sender">KeyDown의 object "sender"</param>
        /// <param name="e">KeyDown의 KeyEventArgs "e"</param>
        public void DataGrid_to_Delete(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                int rowIndex = ((DataGridView)sender).CurrentCell.RowIndex;
                int columnIndex = ((DataGridView)sender).CurrentCell.ColumnIndex;
                ((DataGridView)sender).Rows[rowIndex].Cells[columnIndex].Value = "";
            }
        }
        /// <summary>
        /// RowPostPaint 이벤트 핸들러
        /// 그리드 앞 머리말에 넘버를 표시
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Print_Grid_Num(Object sender, DataGridViewRowPostPaintEventArgs e)
        {
            // 
            // 행헤더 열영역에 행번호를 위해 장방형으로 처리

            Rectangle rect = new Rectangle(e.RowBounds.Location.X,
                                           e.RowBounds.Location.Y,
                                           ((DataGridView)sender).RowHeadersWidth - 4,
                                           e.RowBounds.Height);
            // 위에서 생성된 장방형내에 행번호를 보여주고 폰트색상 및 배경을 설정
            TextRenderer.DrawText(e.Graphics,
                                  (e.RowIndex + 1).ToString(),
                                  ((DataGridView)sender).RowHeadersDefaultCellStyle.Font,
                                  rect,
                                  ((DataGridView)sender).RowHeadersDefaultCellStyle.ForeColor,
                                  TextFormatFlags.VerticalCenter | TextFormatFlags.Right);
        }
        /// <summary>
        /// Grid에서 복사시 클립보드 글자깨짐방지
        /// 현재 효과없음
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void clipboard_not_crack(object sender, KeyEventArgs e)
        {
            Clipboard.SetDataObject(((DataGridView)sender).GetClipboardContent().GetText());
        }


        #region DataGridView 드래그 행이동 이벤트 함수
        private Rectangle dragBoxFromMouseDown;
        private int rowIndexFromMouseDown;
        private int rowIndexOfItemUnderMouseToDrop;

        public void MouseMove(object sender, MouseEventArgs e)
        {
            DataGridView dataGridView = sender as DataGridView;

            if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
            {
                if (dragBoxFromMouseDown != Rectangle.Empty && !dragBoxFromMouseDown.Contains(e.X, e.Y))
                {
                    DragDropEffects dropEffect = dataGridView.DoDragDrop(dataGridView.Rows[rowIndexFromMouseDown], DragDropEffects.Move);
                }
            }
        }

        public void MouseDown(object sender, MouseEventArgs e)
        {
            DataGridView dataGridView = sender as DataGridView;
            rowIndexFromMouseDown = dataGridView.HitTest(e.X, e.Y).RowIndex;
            if (rowIndexFromMouseDown != -1)
            {
                Size dragSize = SystemInformation.DragSize;

                dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2), e.Y - (dragSize.Height / 2)), dragSize);
            }
            else
                dragBoxFromMouseDown = Rectangle.Empty;
        }

        public void DragOver(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Move;
        }

        public void DragDrop(object sender, DragEventArgs e)
        {
            DataGridView dataGridView = sender as DataGridView;

            Point clientPoint = dataGridView.PointToClient(new Point(e.X, e.Y));

            rowIndexOfItemUnderMouseToDrop = dataGridView.HitTest(clientPoint.X, clientPoint.Y).RowIndex;

            if (e.Effect == DragDropEffects.Move)
            {
                DataGridViewRow rowToMove = e.Data.GetData(typeof(DataGridViewRow)) as DataGridViewRow;
                dataGridView.Rows.RemoveAt(rowIndexFromMouseDown);
                dataGridView.Rows.Insert(rowIndexOfItemUnderMouseToDrop, rowToMove);
            }
        }

        #endregion
    }
    class Excel_text
    {
        /// <summary>
        /// 주문관리 - Excel로 주문서 작성하는 노가다코드
        /// </summary>
        /// <param name="data">Grid상 선택된 데이터가 해당 배열변수에 들어감</param>
        /// <param name="total">Grid상 선택된 데이터중 개수의 합계</param>
        /// <param name="compidx">사용자가 소속된 회사 인덱스</param>
        /// <param name="Pur">주문처명</param>
        /// <param name="PS">엑셀 밑부분에 붙힐 참고사항</param>
        /// <returns>생성된 파일명</returns>
        public string mk_Excel_Order(string[,] data, int[] total, string compidx, string Pur, string PS)
        {
            Helper_DB db = new Helper_DB();
            db.DBcon();

            if (Pur == "") { UTIL.MsgE("입력된 주문처가 없습니다!"); return "False"; }

            string Area = "`comp_name`, `tel`, `fax`, `bubin`, `uptae`, " +
                          "`jongmok`, `addr`, `boss`, `email`, `barea`";

            string Pur_Area = "`tel`, `fax`, `emchk`";

            string cmd1 = db.DB_Select_Search(Area, "Comp", "idx", compidx);
            string cmd2 = db.DB_Select_Search(Pur_Area, "Purchase", "sangho", Pur);

            string db_res1 = db.DB_Send_CMD_Search(cmd1);
            string db_res2 = db.DB_Send_CMD_Search(cmd2);

            string[] db_data = db_res1.Split('|');
            string[] db_pur = db_res2.Split('|');

            if (db_res1.Length < 3)
            {
                UTIL.MsgE("DB호출 에러!");
                return "False";
            }
            string tel = string.Empty;
            string fax = string.Empty;
            string emchk = string.Empty;

            if (db_pur.Length > 3)
            {
                for (int a = 0; a < db_pur.Length; a++)
                {
                    if (a % 3 == 0)
                    {   // 전화번호
                        if (db_pur[a] != "")
                        {
                            tel = db_pur[a];
                        }
                    }
                    if (a % 3 == 1)
                    {   // 팩스
                        if (db_pur[a] != "")
                        {
                            fax = db_pur[a];
                        }
                    }
                    if (a % 3 == 2)
                    {   // 팩스 이메일 체크
                        emchk = db_pur[a];
                    }
                }
            }
            try
            {
                string tempPath = Application.StartupPath + "\\Excel";
                DirectoryInfo di = new DirectoryInfo(tempPath);
                if (!di.Exists) { di.Create(); }

                Excel.Application application = new Excel.Application();    // Excel Application Create
                // application.Visible = true;         // true 일시 엑셀이 작업되는 내용이 보임
                // application.Interactive = false;    // false일 경우 유저의 조작에 방해받지않음.

                Excel._Workbook wb = (Excel._Workbook)(application.Workbooks.Add(Missing.Value));   // 워크북 생성
                Excel._Worksheet ws = (Excel._Worksheet)application.ActiveSheet;    // 시트 가져옴
                Excel.PageSetup ps = ws.PageSetup;

                ps.LeftMargin = 0.64;
                ps.RightMargin = 0.64;
                ps.TopMargin = 1.91;
                ps.BottomMargin = 1.91;

                Excel.Range rng = null;     // 셀 처리 변수
                Excel.Range rng2 = null;     // 셀 처리 변수2

                // 발신자 정보
                string compname = db_data[0];
                string Snum = db_data[1];
                string Sfax = db_data[2];
                string Scompnum = db_data[3];
                string 업태 = db_data[4];
                string 종목 = db_data[5];
                string 주소 = db_data[6];
                string 대표 = db_data[7];
                string 이메일 = db_data[8];
                string[] barea = { "한국출판물류", "드 림  날 개", "모든배본대행", db_data[9] };

                // 수신자 정보
                string taker = Pur;
                string Tnum = tel;
                string Tfax = fax;

                // 엑셀 파일 이름 설정
                string now = DateTime.Now.ToString("yy-MM-dd-HH-mm");
                string FileName = string.Format("{0}_{1}_{2}_{3}.xlsx", now.Replace("-", ""), emchk, Pur, db_data[0]);
                UTIL.MsgI(FileName);

                // 엑셀 파일 저장 경로
                string Savepath = Path.Combine(tempPath, FileName);

                #region 엑셀 베이스 (셀의 너비, 높이 설정)
                ws.Columns[1].ColumnWidth = 3;      // A
                ws.Columns[2].ColumnWidth = 12;     // B
                ws.Columns[3].ColumnWidth = 28;     // C
                ws.Columns[4].ColumnWidth = 9;      // D
                ws.Columns[5].ColumnWidth = 4;      // E
                ws.Columns[6].ColumnWidth = 9;      // F
                ws.Columns[7].ColumnWidth = 12;     // G

                ws.Rows[1].RowHeight = 16.5;
                ws.Rows[2].RowHeight = 30;
                ws.Rows[3].RowHeight = 10;
                ws.Rows[4].RowHeight = 22;
                ws.Rows[5].RowHeight = 22;
                ws.Rows[6].RowHeight = 22;
                ws.Rows[7].RowHeight = 22;
                ws.Rows[8].RowHeight = 22;
                ws.Rows[9].RowHeight = 16.5;
                ws.Rows[10].RowHeight = 24;
                #endregion

                rng = ws.Range["A4", "G8"];
                rng.Borders.LineStyle = Excel.XlLineStyle.xlContinuous;

                // 제목 셀
                rng = ws.Range["A2", "G2"];
                rng.MergeCells = true;
                rng.Value2 = "도 서 주 문 서";
                rng.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;
                rng.Font.Bold = true;
                rng.Font.Size = 22;

                // 기본 정보 입력칸
                #region 주문일자 / 보낸곳 (4행)
                rng = ws.Range["A4", "C4"];
                rng.MergeCells = true;
                rng.Value2 = "주문일자 : " + DateTime.Now.ToString("yyyy-MM-dd H:m:ss");
                rng.HorizontalAlignment = Excel.XlHAlign.xlHAlignLeft;
                rng.Font.Bold = true;

                rng2 = ws.Range["D4", "G4"];
                rng2.MergeCells = true;
                rng2.Value2 = "보낸곳 : " + compname;
                rng2.HorizontalAlignment = Excel.XlHAlign.xlHAlignLeft;
                rng2.Font.Bold = true;
                rng2.Font.Size = 14;
                #endregion

                #region 받는곳 / 보낸곳 전화번호 (5행)
                rng = ws.Range["A5", "C5"];
                rng.MergeCells = true;
                rng.Value2 = "받 는 곳 : " + taker;
                rng.HorizontalAlignment = Excel.XlHAlign.xlHAlignLeft;
                rng.Font.Bold = true;

                rng2 = ws.Range["D5", "G5"];
                rng2.MergeCells = true;
                rng2.Value2 = "전화번호 : " + Snum;
                rng2.HorizontalAlignment = Excel.XlHAlign.xlHAlignLeft;
                rng2.Font.Bold = true;
                #endregion

                #region 받는곳 전화번호 / 보낸곳 팩스번호 (6행)
                rng = ws.Range["A6", "C6"];
                rng.MergeCells = true;
                rng.Value2 = "전화번호 : " + Tnum;
                rng.HorizontalAlignment = Excel.XlHAlign.xlHAlignLeft;
                rng.Font.Bold = true;

                rng2 = ws.Range["D6", "G6"];
                rng2.MergeCells = true;
                rng2.Value2 = "팩스 : " + Sfax;
                rng2.HorizontalAlignment = Excel.XlHAlign.xlHAlignLeft;
                rng2.Font.Bold = true;
                #endregion

                #region 받는곳 팩스번호 / 보낸곳 사업자등록번호 (7행)
                rng = ws.Range["A7", "C7"];
                rng.MergeCells = true;
                rng.Value2 = "팩스 : " + Tfax;
                rng.HorizontalAlignment = Excel.XlHAlign.xlHAlignLeft;
                rng.Font.Bold = true;

                rng2 = ws.Range["D7", "G7"];
                rng2.MergeCells = true;
                rng2.Value2 = "사업자No : " + Scompnum;
                rng2.HorizontalAlignment = Excel.XlHAlign.xlHAlignLeft;
                rng2.Font.Bold = true;
                #endregion

                #region 보낸곳 업태, 종목, 주소, 대표자 (8행)
                rng2 = ws.Range["A8", "G8"];
                rng2.MergeCells = true;
                rng2.Value2 = string.Format(@"배송주소 : {0}", 주소);
                rng2.HorizontalAlignment = Excel.XlHAlign.xlHAlignLeft;
                rng2.Font.Bold = true;
                rng2.WrapText = true;
                #endregion

                // 도서 주문 목록 입력칸 (idx가 정해져있지않음)
                #region 표 헤더 (No / 출판사 / 도서명 / 저자 / 수량 / 정가 / 구분 (10행)
                string[] Header = { "No", "출판사", "도서명", "저자", "수량", "정가", "구분" };
                rng = ws.Range["A10", "G10"];
                rng.Value2 = Header;
                rng.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;
                rng.Font.Bold = true;
                #endregion

                #region gridData 엑셀에 반영 (11행~)
                int endcount = data.GetLength(0) + 10;
                rng2 = ws.Range["A11", "G" + endcount];
                rng2.Value2 = data;
                rng2.Borders.LineStyle = Excel.XlLineStyle.xlContinuous;
                rng2.RowHeight = 24;
                rng2.WrapText = true;
                rng.Borders.LineStyle = Excel.XlLineStyle.xlContinuous;

                string[] total_array = { "", "합계", "", "", total[0].ToString(), total[1].ToString(), "" };

                endcount++;
                rng = ws.Range["A" + endcount, "G" + endcount];
                rng.Value2 = total_array;
                rng.Font.Bold = true;

                rng2 = ws.Range["E11", "G" + endcount];
                rng2.HorizontalAlignment = Excel.XlHAlign.xlHAlignRight;
                #endregion

                #region 추신
                endcount++;
                string 발송처 = "D" + endcount.ToString();

                rng = ws.Range["A" + endcount, "C" + endcount];
                rng.MergeCells = true;
                rng.Value2 = "계산서 또는 세금계산서를 발행해주세요.";
                rng.Font.Bold = true;

                rng2 = ws.Range["E" + endcount, "F" + endcount];
                rng2.MergeCells = true;
                rng2.Value2 = barea[0];
                rng2.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;
                rng2.Font.Bold = true;

                ////////
                endcount++;

                rng = ws.Range["A" + endcount, "C" + endcount];
                rng.MergeCells = true;
                rng.Value2 = "E-Mail : " + 이메일;
                rng.Font.Bold = true;

                rng2 = ws.Range["E" + endcount, "F" + endcount];
                rng2.MergeCells = true;
                rng2.Value2 = barea[1];
                rng2.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;
                rng2.Font.Bold = true;

                ////////
                endcount++;

                rng = ws.Range["A" + endcount, "C" + endcount];
                rng.MergeCells = true;
                rng.Value2 = "품절 및 절판도서는 연락주세요.";
                rng.Font.Bold = true;

                rng2 = ws.Range["E" + endcount, "F" + endcount];
                rng2.MergeCells = true;
                rng2.Value2 = barea[2];
                rng2.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;
                rng2.Font.Bold = true;

                ////////
                endcount++;

                rng = ws.Range["A" + endcount, "C" + endcount];
                rng.MergeCells = true;
                rng.Value2 = "거레명세표를 발행하여 Fax번호로 회신부탁드립니다.";
                rng.Font.Bold = true;

                rng2 = ws.Range["E" + endcount, "F" + endcount];
                rng2.MergeCells = true;
                rng2.Value2 = barea[3];
                rng2.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;
                rng2.Font.Bold = true;

                ////////
                rng = ws.Range[발송처, "D" + endcount];
                rng.MergeCells = true;
                rng.Value2 = "발 송 처";
                rng.Font.Bold = true;
                rng.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;

                ////////
                rng2 = ws.Range[발송처, "F" + endcount];
                rng2.Borders.LineStyle = Excel.XlLineStyle.xlContinuous;

                #endregion

                #region 마무리 다듬기
                endcount++;
                rng = ws.Range["A" + endcount, "G" + endcount];
                rng.Value2 = PS;
                rng.MergeCells = true;
                rng.Interior.Color = ColorTranslator.ToOle(Color.LightGray);

                rng2 = ws.Range["A4", "G" + endcount];
                rng2.Font.Name = "돋음";
                rng2.Font.Size = 10;
                #endregion

                wb.SaveAs(Savepath, Excel.XlFileFormat.xlWorkbookDefault);
                wb.Close(true);

                application.Interactive = true;
                application.Quit();

                return FileName;
            }
            catch (Exception e)
            {
                UTIL.MsgE(e.ToString());
                return "False";
            }
        }

        /// <summary>
        /// 엑셀 내보내기
        /// </summary>
        /// <param name="data">사용할 데이터</param>
        public void Mk_Excel(string[] title, string[,] data)
        {
            try
            {
                Excel.Application app = new Excel.Application();
                app.Visible = true;             // true 일때 엑셀이 작업되는 내용이 보임
                app.Interactive = false;        // false 일때 유저의 조작에 방해받지않음.

                Excel._Workbook wb = (Excel._Workbook)(app.Workbooks.Add(Missing.Value));   // 워크북 생성
                Excel._Worksheet ws = (Excel._Worksheet)app.ActiveSheet;    // 시트 가져옴
                Excel.PageSetup ps = ws.PageSetup;

                Excel.Range rng = null;     // 셀 처리 변수

                rng = ws.Range["A1", Excel_Sub(title) + "1"];
                rng.Font.Color = Color.Blue;
                rng.HorizontalAlignment = 3;
                rng.Value2 = title;

                int length = data.GetLength(0) + 1;
                rng = ws.Range["A2", Excel_Sub(title) + length];
                rng.Value2 = data;
                ws.Columns.AutoFit();

                app.Interactive = true;
                //app.Quit();
            }
            catch (Exception e)
            {
                UTIL.MsgE(e.ToString());
            }
        }
        #region MK_Excel_Sub
        private string Excel_Sub(string[] data)
        {
            string[] length = {
                "1", "2", "3", "4", "5",
                "6", "7", "8", "9", "10",
                "11", "12", "13", "14", "15",
                "16", "17", "18", "19", "20",
                "21", "22", "23", "24", "25", "26"
            };
            string[] Alpha = {
                "A", "B", "C", "D", "E",
                "F", "G", "H", "I", "J",
                "K", "L", "M", "N", "O",
                "P", "Q", "R", "S", "T",
                "U", "V", "W", "X", "Y", "Z"
            };

            string count = data.Length.ToString();
            string res = string.Empty;

            for (int a = 0; a < length.Length; a++)
            {
                if (length[a] == count)
                {
                    res = Alpha[a];
                }
            }
            return res;
        }
        #endregion
    }
    public class Helper_Print
    {
        /// <summary>
        /// 행의 갯수
        /// </summary>
        public int cnt = 0;

        /// <summary>
        /// 페이지 넘버
        /// </summary>
        public int pageNo = 1;

        public void Init()
        {
            cnt = 0;
            pageNo = 1;
        }

        public void PrintPage(object sender, PrintPageEventArgs e, DataGridView gridView)
        {
            // 페이지 전체넓이
            int dialogWidth = 528;

            // 컬럼 안에 있는 값들 가운데 정렬하기 위해 선언
            StringFormat sf = new StringFormat();
            sf.Alignment = StringAlignment.Center;

            // width는 시작점 위치, width1은 datagrid 1개의 컬럼 가로길이
            int width, width1;

            // 시작 x좌표
            int startWidth = 10;

            // 시작 y좌표
            int startHeight = 140;

            // gridView 컬럼 하나의 높이
            int avgHeight = gridView.Rows[0].Height;

            // row 개수 카운트용
            int temp = 0;

            e.Graphics.DrawString("제목", new Font("Arial", 20, FontStyle.Bold), Brushes.Black, dialogWidth / 2, 40);
            e.Graphics.DrawString("인쇄일 : " + DateTime.Now.ToString("yyyy/MM/dd"), new Font("Arial", 13), Brushes.Black, dialogWidth - 20, 80);
            e.Graphics.DrawString("페이지번호 : " + pageNo, new Font("Arial", 13), Brushes.Black, dialogWidth - 20, 100);

            for (int a = 0; a < gridView.ColumnCount; a++)
            {
                if (a == 0)
                {
                    width = 0;
                    width1 = gridView.Columns[a].Width + 15;
                }
                else if (a >= 1 && a < gridView.ColumnCount - 2)
                {
                    width = gridView.Columns[a - 1].Width + 15;
                    width1 = gridView.Columns[a].Width + 15;
                }
                else
                {
                    width = gridView.Columns[a - 1].Width + 15;
                    width1 = gridView.Columns[a].Width + 40;
                }

                RectangleF drawRect = new RectangleF((float)(startWidth + width), (float)startHeight, (float)width1, avgHeight);

                e.Graphics.DrawRectangle(Pens.Black, (float)(startWidth + width), (float)startHeight, (float)width1, avgHeight);

                // e.Graphics.FillRectangle(Brushes.LightGray, (float)(startWidth + width), (float)startHeight, (float)width1, avgHeight);
                e.Graphics.DrawString(gridView.Columns[a].HeaderText, new Font("Arial", 12, FontStyle.Bold), Brushes.Black, drawRect, sf);

                startWidth += width;
            }
            startHeight += avgHeight;

            for (int a = cnt; a < gridView.RowCount - 1; a++)
            {
                startWidth = 10;    // 다시 초기화
                for (int b = 0; b < gridView.ColumnCount; b++)
                {
                    if (b == 0)
                    {
                        width = 0;
                        width1 = gridView.Columns[b].Width + 15;
                    }
                    else if (b >= 1 && b <= gridView.ColumnCount - 2)
                    {
                        width = gridView.Columns[b - 1].Width + 15;
                        width1 = gridView.Columns[b].Width + 15;
                    }
                    else
                    {
                        width = gridView.Columns[b - 1].Width + 15;
                        width1 = gridView.Columns[b].Width + 40;
                    }

                    RectangleF drawRect = new RectangleF((float)(startWidth + width), (float)startHeight, (float)width1, avgHeight);

                    e.Graphics.DrawRectangle(Pens.Black, (float)(startWidth + width), (float)startHeight, (float)width1, avgHeight);

                    //e.Graphics.FillRectangle(Brushes.LightGray, (float)(startWidth + width), (float)startHeight, (float)width, avgHeight);
                    e.Graphics.DrawString(gridView.Rows[a].Cells[b].FormattedValue.ToString(), new Font("Arial", 9), Brushes.Black, drawRect, sf);
                    startHeight += width;
                }
                startHeight += avgHeight;
                temp++;
                cnt++;

                if (temp % 40 == 0)
                {
                    e.HasMorePages = true;
                    pageNo++;
                    return;
                }
            }
        }
    }

    class Barobill_FAX
    {
        private string CERTKEY = "BC5F164E-6410-44FF-BADF-25732E850D36";    //인증키
        private string CorpNum = "4088188534";                //바로빌 회원 사업자번호 ('-' 제외, 10자리) 		
        private string SenderID = "gloriabook";               //연계사업자 담당자 아이디

        /// <summary>
        /// 팩스 전송 모듈 (21.04.08 주문관리 전용)
        /// </summary>
        /// <param name="file_name"></param>
        /// <param name="fax_param">[0] 발신번호 / [1] 수신번호
        /// / [2] 수신자 회사명 / [3 ]수신자명 </param>
        public string Send_BaroFax(string file_name, string[] fax_param)
        {
            BaroService_FAXSoapClient fAXSoapClient = new BaroService_FAXSoapClient();

            string FileName = file_name;               //전송할 파일명
            string FromNumber = fax_param[0];             //발신번호
            string ToNumber = fax_param[1];               //수신번호
            string ToCorpName = fax_param[2];             //수신자 회사명
            string ToName = fax_param[3];                 //수신자명
            string SendDT = "";                 //전송일시 (yyyyMMddHHmmss 형식) (빈 문자열 입력시 즉시 전송, 미래일자 입력시 예약 전송)
            string RefKey = "";                 //연동사부여 전송키

            string result = fAXSoapClient.SendFaxFromFTP(
                CERTKEY, CorpNum, SenderID, FileName, FromNumber,
                ToNumber, ToCorpName, ToName, SendDT, RefKey);
            string msg = string.Format(@"[{0}] 파일이 팩스로 전송되었습니다!", FileName);

            string ErrMsg = FAX_GetErrString(result);
            if (ErrMsg != "")
                UTIL.MsgI(msg);
            else
                UTIL.MsgE(ErrMsg);

            return result;
        }

        /// <summary>
        /// 전송 성공여부 확인
        /// </summary>
        /// <param name="sendkey">전송된 결과값</param>
        /// <returns></returns>
        public string[] Send_chk_BaroFax(string sendkey)
        {
            BaroService_FAXSoapClient fAXSoapClient = new BaroService_FAXSoapClient();

            // 수신자회사명, 수신번호, 전송일시, 전송결과, 전송페이지수, 성공페이지수, 전송파일명
            string[] MsgBox_Array = {
                fAXSoapClient.GetFaxMessage(CERTKEY, CorpNum, sendkey).ReceiveCorp,
                fAXSoapClient.GetFaxMessage(CERTKEY, CorpNum, sendkey).ReceiverNum,
                fAXSoapClient.GetFaxMessage(CERTKEY, CorpNum, sendkey).SendDT,
                fAXSoapClient.GetFaxMessage(CERTKEY, CorpNum, sendkey).SendResult,
                fAXSoapClient.GetFaxMessage(CERTKEY, CorpNum, sendkey).SendPageCount.ToString(),
                fAXSoapClient.GetFaxMessage(CERTKEY, CorpNum, sendkey).SuccessPageCount.ToString(),
                fAXSoapClient.GetFaxMessage(CERTKEY, CorpNum, sendkey).SendFileName
            };

            MsgBox_Array[3] = Msg_result(MsgBox_Array[3]);

            return MsgBox_Array;
        }

        /// <summary>
        /// 코드에 따른 오류 메시지 반환
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        private string FAX_GetErrString(string msg)
        {
            switch (msg)
            {
                #region 공통 오류
                // 기본 오류코드
                case "-10000": return "알 수 없는 오류 발생.";
                case "-10003": return "연동 서비스가 점검중입니다.";
                case "-10004": return "해당 기능은 더 이상 사용되지 않습니다.";
                case "-10005": return "최대 100건까지만 사용하실 수 있습니다.";
                case "-10006": return "최대 1000건까지만 사용하실 수 있습니다.";
                case "-10007": return "해당 기능을 사용할 수 없습니다.";
                case "-10008": return "날짜형식이 잘못되었습니다.";
                case "-10148": return "조회 기간이 잘못되었습니다.";
                case "-40001": return "파일을 찾을 수 없습니다.";
                case "-40002": return "빈 파일입니다. (0Byte)";

                // 연동정보 관련
                case "-10002": return "해당 인증키를 찾을 수 없습니다.";
                case "-10001": return "해당 인증키와 연결된 연계사가 아닙니다.";
                case "-24005": return "사업자번호와 아이디가 맞지 않습니다.";

                // 회원정보 관련
                case "-32000": return "이미 가입된 연계사업자입니다.";
                case "-32001": return "사업자번호가 유효하지 않습니다.";
                case "-32002": return "회사명이 유효하지 않습니다.";
                case "-32003": return "대표자명이 유효하지 않습니다.";
                case "-32004": return "업태가 유효하지 않습니다.";
                case "-32005": return "업종이 유효하지 않습니다.";
                case "-32006": return "주소가 유효하지 않습니다.";
                case "-32008": return "담당자명이 유효하지 않습니다.";
                case "-32010": return "아이디가 유효하지 않습니다.";
                case "-32015": return "해당 아이디는 이미 사용중입니다.";
                case "-32011": return "패스워드가 유효하지 않습니다.";
                case "-32012": return "연락처가 유효하지 않습니다.";
                case "-32013": return "이메일이 유효하지 않습니다.";
                case "-32016": return "해당 아이디를 찾을 수 없습니다.";
                case "-32017": return "탈퇴한 아이디입니다.";

                // 과금 관련
                case "-26014": return "과금코드를 찾을 수 없습니다.";
                case "-26004": return "과금에 실패하였습니다.";
                case "-26006": return "충전잔액이 부족합니다.";
                case "-26011": return "연동사의 충전잔액이 부족합니다.";
                case "-26015": return "공급받는자의 충전잔액이 부족합니다.";
                #endregion

                #region 문서서비스 관련
                // 문서 서비스 공통
                case "-24011": return "문서 DB입력에 실패하였습니다.";
                case "-24012": return "문서 품목정보 DB입력에 실패하였습니다.";
                case "-24013": return "문서 속성정보 DB입력에 실패하였습니다.";
                case "-34021": return "문서 DB수정에 실패하였습니다.";
                case "-34022": return "문서 품목정보 DB수정에 실패하였습니다.";
                case "-34023": return "문서 속성정보 DB수정에 실패하였습니다.";
                case "-25102": return "관리번호(MgtKey)가 잘못되었습니다.";
                case "-11013": return "관리번호(MgtKey)가 중복되었습니다.";
                case "-11011": return "공급자 부여 관리번호(MgtKey)가 잘못되었습니다.";
                case "-11012": return "공급받는자 부여 관리번호(MgtKey)가 잘못되었습니다.";
                case "-11018": return "수탁자 부여 관리번호(MgtKey)가 잘못되었습니다.";
                case "-21002": return "해당 문서 정보가 없습니다.";
                case "-21003": return "해당 문서는 삭제 가능한 상태가 아닙니다.";
                case "-21005": return "해당 문서는 임시저장상태가 아닙니다.";
                case "-21006": return "해당 문서는 임시저장상태입니다.";
                case "-26000": return "해당 문서는 이미 발행되었거나, 임시저장상태가 아니므로 발행이 불가능합니다.";
                case "-21007": return "해당 문서는 취소 가능한 상태가 아닙니다.";
                case "-30000": return "지원되지 않는 처리요청입니다. (ProcType)";
                case "-30001": return "해당 처리요청은 현재 상태에는 처리할 수 없습니다.";
                case "-25101": return "문서형태가 올바르지 않습니다.";
                case "-26009": return "처리에 실패하였습니다.";
                case "-33000": return "첨부할 파일을 찾을 수 없습니다.";
                case "-33001": return "첨부파일 개수가 제한을 초과하였습니다.";
                case "-33002": return "일괄인쇄기능은 50건까지만 가능합니다";

                // 세금계산서 관련
                case "-11009": return "문서 형태가 잘못되었습니다. (TaxInvoiceType)";
                case "-11019": return "계산서 형태가 맞지 않습니다. (TaxInvoiceType, TaxType)";
                case "-11010": return "과세형태가 잘못되었습니다. (TaxType)";
                case "-11007": return "영수/청구 구분이 잘못되었습니다. (PurposeType)";
                case "-11005": return "발행방향이 잘못되었습니다. (IssueDirection)";
                case "-11008": return "세금계산방식이 잘못되었습니다. (TaxCalcType)";
                case "-24006": return "발행시점이 잘못되었습니다. (IssueTiming)";
                case "-11110": return "공급자와 공급받는자의 사업자번호가 같습니다.";
                case "-11002": return "공급자 정보가 없습니다. (InvoicerParty)";
                case "-11101": return "공급자 사업자번호가 잘못되었습니다. (InvoicerParty.CorpNum)";
                case "-11109": return "공급자의 종사업자 번호는 숫자 4자리로 입력해야 합니다. (InvoicerParty.TaxRegID)";
                case "-11102": return "공급자 상호가 잘못되었습니다. (InvoicerParty.CorpName)";
                case "-11103": return "공급자 대표자명이 잘못되었습니다. (InvoicerParty.CEOName)";
                case "-11104": return "공급자 주소가 잘못되었습니다. (InvoicerParty.Addr)";
                case "-11105": return "공급자 업종이 잘못되었습니다. (InvoicerParty.BizType)";
                case "-11106": return "공급자 업태가 잘못되었습니다. (InvoicerParty.BizClass)";
                case "-11001": return "공급자 아이디가 잘못되었습니다. (InvoicerParty.ContactID)";
                case "-11107": return "공급자 담당자명이 잘못되었습니다. (InvoicerParty.ContactName)";
                case "-11108": return "공급자 이메일이 잘못되었습니다. (InvoicerParty.Email)";
                case "-11003": return "공급받는자 정보가 없습니다. (InvoiceeParty)";
                case "-11201": return "공급받는자 사업자번호가 잘못되었습니다. (InvoiceeParty.CorpNum)";
                case "-11209": return "공급받는자의 종사업자 번호는 숫자 4자리로 입력해야 합니다. (InvoiceeParty.TaxRegID)";
                case "-11202": return "공급받는자 상호가 잘못되었습니다. (InvoiceeParty.CorpName)";
                case "-11203": return "공급받는자 대표자명이 잘못되었습니다. (InvoiceeParty.CEOName)";
                case "-11204": return "공급받는자 주소가 잘못되었습니다. (InvoiceeParty.Addr)";
                case "-11205": return "공급받는자 업종이 잘못되었습니다. (InvoiceeParty.BizType)";
                case "-11206": return "공급받는자 업태가 잘못되었습니다. (InvoiceeParty.BizClass)";
                case "-11017": return "공급받는자 아이디가 잘못되었습니다. (InvoiceeParty.ContactID)";
                case "-11207": return "공급받는자 담당자명이 잘못되었습니다. (InvoiceeParty.ContactName)";
                case "-11208": return "공급받는자 이메일이 잘못되었습니다. (InvoiceeParty.Email)";
                case "-11004": return "위탁자 정보가 없습니다. (BrokerParty)";
                case "-25003": return "위탁자 사업자번호가 잘못되었습니다 (BrokerParty.CorpNum).";
                case "-11210": return "위탁자의 종사업자 번호는 숫자 4자리로 입력해야 합니다. (BrokerParty.TaxRegID)";
                case "-11301": return "수탁자 사업자번호가 잘못되었습니다. (BrokerParty.CorpNum)";
                case "-11302": return "수탁자 상호가 잘못되었습니다. (BrokerParty.CorpName)";
                case "-11303": return "수탁자 대표자명이 잘못되었습니다. (BrokerParty.CEOName)";
                case "-11304": return "수탁자 주소가 잘못되었습니다. (BrokerParty.Addr)";
                case "-11305": return "수탁자 업종이 잘못되었습니다. (BrokerParty.BizType)";
                case "-11306": return "수탁자 업태가 잘못되었습니다. (BrokerParty.BizClass)";
                case "-11014": return "수탁자 아이디가 잘못되었습니다. (BrokerParty.ContactID)";
                case "-11307": return "수탁자 담당자명이 잘못되었습니다. (BrokerParty.ContactName)";
                case "-11308": return "수탁자 이메일이 잘못되었습니다. (BrokerParty.Email)";
                case "-11021": return "공급받는자가 외국인인 경우 비고에 추가정보를 기재하여야 합니다. (Remark1)";
                case "-11022": return "작성일자의 형식(YYYYMMDD)이 잘못되었습니다. (WriteDate)";
                case "-11020": return "작성일자를 미래일자로 발행하실 수 없습니다. (WriteDate)";
                case "-11801": return "권 항목이 잘못되었습니다. 숫자만 가능합니다. (Kwon)";
                case "-11802": return "호 항목이 잘못되었습니다. 숫자만 가능합니다. (Ho)";
                case "-11006": return "공급가액이 잘못되었습니다. (AmountTotal)";
                case "-11016": return "세액이 잘못되었습니다. (TaxTotal)";
                case "-11015": return "합계금액이 잘못되었습니다. (TotalAmount)";
                case "-11310": return "영세,면세 세금계산서는 세금이 0원이어야 합니다.";
                case "-11311": return "과세는 세금이 0원 이상이어야 합니다.";
                case "-11803": return "현금 항목이 잘못되었습니다. (Cash)";
                case "-11804": return "수표 항목이 잘못되었습니다. (ChkBill)";
                case "-11805": return "어음 항목이 잘못되었습니다. (Note)";
                case "-11806": return "외상미수금 항목이 잘못되었습니다. (Credit)";
                case "-11811": return "현금, 수표, 어음, 외상미수금의 합계가 세금계산서의 합계금액과 맞지 않습니다.";
                case "-11309": return "품목정보는 99개까지만 입력할 수 있습니다. (TaxInvoiceTradeLineItems)";
                case "-11023": return "품목정보의 공급일자 형식(YYYYMMDD)이 잘못되었습니다. (TaxInvoiceTradeLineItem.PurchaseExpiry)";
                case "-11814": return "품목정보의 공급일자의 월은 작성일자의 월과 같아야 합니다. (TaxInvoiceTradeLineItem.PurchaseExpiry)";
                case "-11808": return "품목정보의 수량이 유효하지 않습니다. (TaxInvoiceTradeLineItem.ChargeableUnit)";
                case "-11809": return "품목정보의 단가가 유효하지 않습니다. (TaxInvoiceTradeLineItem.UnitPrice)";
                case "-11807": return "품목정보의 공급가액이 유효하지 않습니다. (TaxInvoiceTradeLineItem.Amount)";
                case "-11810": return "품목정보의 세액이 유효하지 않습니다. (TaxInvoiceTradeLineItem.Tax)";
                case "-11812": return "품목정보의 공급가액, 세액이 유효하지 않습니다.";
                case "-11813": return "영세,면세 세금계산서는 품목정보의 세금이 0원이어야 합니다.";
                case "-11321": return "해당 함수는 일반세금계산서를 등록하실 수 없습니다.";
                case "-11322": return "당초 국세청승인번호가 입력되지 않았습니다.";
                case "-11323": return "당초 국세청승인번호는 바로빌을 통해 등록된 세금계산서의 승인번호만 가능합니다.";
                case "-11324": return "공급자의 당초 국세청승인번호가 아닙니다.";
                case "-11330": return "일반세금계산서를 수정세금계산서로 수정하실 수 없습니다.";
                case "-11331": return "수정세금계산서를 일반세금계산서로 수정하실 수 없습니다.";
                case "-11332": return "\"과세,영세\" 와 \"면세\" 간에 수정세금계산서를 작성하실 수 없습니다.";
                case "-11341": return "환입 또는 계약의해지 시 공급가액과 세액은 (-)이어야 합니다.";
                case "-26012": return "해당 세금계산서에 대해 가산세가 예상됩니다.";
                case "-26013": return "해당 세금계산서에 대해 과세기간이 종료하였거나, 발행대상이 아닙니다.";
                case "-26005": return "해당 세금계산서의 전자서명 과정 중 XML생성에 실패하였습니다.";
                case "-31002": return "해당 세금계산서는 국세청 전송이 불가한 상태입니다.";
                case "-31004": return "국세청 신고 과정이 진행 중이거나, 완료되었습니다.";
                case "-31007": return "해당 세금계산서의 전자서명 정보를 찾을 수 없습니다.";
                case "-31008": return "국세청 신고요청 중 알수 없는 오류가 발생하였습니다.";
                case "-31009": return "역발행으로 저장된 건이 아닙니다.";

                // 세금계산서 국세청 전송설정 관련
                case "-31015": return "\"과세\" 국세청 전송설정을 잘못 설정하였습니다.";
                case "-31016": return "\"과세\" 지연발행 허용 여부를 잘못 설정하였습니다.";
                case "-31017": return "\"면세\" 국세청 전송설정을 잘못 설정하였습니다.";
                case "-31018": return "\"면세\" 지연발행 허용 여부를 잘못 설정하였습니다.";

                // 공동인증서 관련
                case "-31100": return "등록된 공동인증서가 없습니다.";
                case "-26001": return "발행에 필요한 공동인증서가 등록되어 있지 않습니다.";
                case "-26002": return "등록된 공동인증서가 만료일이 지났거나, 전송일 기준 유효하지 않습니다.";
                case "-26003": return "등록된 공동인증서의 검증에 실패하였습니다. 재등록하여 주시기 바랍니다.";

                // 현금영수증 관련
                case "-11701": return "거래일자가 잘못되었습니다. (TradeDate)";
                case "-11702": return "가맹점 사업자번호가 잘못되었습니다. (FranchiseCorpNum)";
                case "-11703": return "가맹점 아이디가 잘못되었습니다. (FranchiseMemberID)";
                case "-11704": return "가맹점 상호가 잘못되었습니다. (FranchiseCorpName)";
                case "-11705": return "가맹점 대표자명이 잘못되었습니다. (FranchiseCEOName)";
                case "-11706": return "가맹점 주소가 잘못되었습니다. (FranchiseAddr)";
                case "-11707": return "가맹점 전화번호가 잘못되었습니다. (FranchiseTel)";
                case "-11708": return "신분확인번호가 잘못되었습니다. (IdentityNum)";
                case "-11709": return "거래구분이 잘못되었습니다. (TradeType)";
                case "-11710": return "거래용도가 잘못되었습니다. (TradeUsage)";
                case "-11711": return "거래방법이 잘못되었습니다. (TradeMethod)";
                case "-11712": return "취소사유가 잘못되었습니다. (CancelType)";
                case "-11713": return "취소대상 승인번호가 잘못되었습니다. (CancelNTSConfirmNum)";
                case "-11714": return "취소대상 거래일자가 잘못되었습니다. (CancelNTSConfirmDate)";
                case "-11715": return "공급가액이 잘못되었습니다. (Amount)";
                case "-11716": return "부가세가 잘못되었습니다. (Tax)";
                case "-11717": return "봉사료가 잘못되었습니다. (ServiceCharge)";
                case "-11720": return "공급가액이 취소 가능한 금액보다 큽니다. (CancelAmount)";
                case "-11721": return "부가세가 취소 가능한 금액보다 큽니다. (CancelTax)";
                case "-11722": return "봉사료가 취소 가능한 금액보다 큽니다. (CancelServiceCharge)";
                case "-21008": return "거래일자가 과거/미래인 경우에는 발행하실 수 없습니다.";
                case "-11718": return "취소중 알 수 없는 오류가 발생하였습니다.";
                case "-31114": return "국세청으로 전송되기 전에는 취소발행하실 수 없습니다.";
                case "-11719": return "승인번호 채번에 실패하였습니다.";
                case "-31111": return "이메일 전송이 불가능한 상태입니다.";
                case "-31112": return "SMS 전송이 불가능한 상태입니다.";
                case "-31113": return "FAX 전송이 불가능한 상태입니다.";

                // 전자문서 관련
                case "-11601": return "전자문서 양식 코드가 유효하지 않습니다. (FormKey)";
                case "-24014": return "해당 문서에서 사용할 수 없는 속성입니다.";
                case "-31102": return "아이디가 잘못되었습니다. (UserID)";
                case "-31213": return "Fax 기능을 지원하지 않는 문서양식입니다.";

                // 이메일 관련
                case "-31104": return "이메일 전송에 필요한 정보가 부족합니다.";
                case "-31105": return "거부된 건은 이메일 재전송이 불가능합니다.";
                #endregion

                #region 스크래핑 서비스 관련
                // 사업자등록 상태조회 관련
                case "-50301": return "일시적으로 휴폐업조회에 실패하였습니다. (잠시 후 다시 시도해주세요.)";

                // 카드조회 관련
                case "-50101": return "카드를 찾을 수 없습니다.";
                case "-50102": return "카드를 조회할 권한이 없습니다.";

                // 계좌조회 관련
                case "-50001": return "계좌를 찾을 수 없습니다.";
                case "-50002": return "계좌를 조회할 권한이 없습니다.";
                case "-50004": return "일일 즉시조회 횟수(10회)를 초과하였습니다.";
                #endregion

                #region 메시징 서비스 관련
                // 문자전송 관련
                case "-10100": return "발송예약시간 계산오류";
                case "-10101": return "해당 발송정보가 없습니다.";
                case "-31101": return "SMS 전송에 필요한 정보가 부족합니다.";
                case "-31103": return "LMS 제목은 40자까지만 입력가능합니다.";
                case "-10123": return "MMS 전송에 필요한 제목이 없습니다.";
                case "-10124": return "MMS 전송에 필요한 이미지 파일정보가 없습니다.";
                case "-10125": return "MMS 전송 가능한 이미지 파일크기를 초과하였습니다.";
                case "-10126": return "MMS 전송 가능한 이미지의 크기를 초과하였습니다.";
                case "-10127": return "MMS 전송 가능한 이미지 타입은 JPG입니다.";
                case "-10170": return "080 수신거부 되었습니다.";
                case "-10190": return "이미 등록된 발신번호입니다.";
                case "-10191": return "번호의 형식이 올바르지 않습니다.";
                case "-10192": return "사전등록되지 않은 발신번호로 문자를 전송할 수 없습니다.";

                // 문자전송 실패코드
                case "-10104": return "음영지역";
                case "-10106": return "메시지 저장 개수 초과";
                case "-10107": return "잘못된 전화번호";
                case "-10116": return "이통사에서 SPAM처리됨";
                case "-10131": return "MMS 미 지원 단말";
                case "-10132": return "중복전송에러";
                case "-10158": return "발송 미허용 시간 때 발송 실패 처리";
                case "-10185": return "웹문자 발신 차단번호";
                case "-10186": return "기타오류";

                // 팩스전송 관련
                case "-31204": return "FAX 전송에 필요한 정보가 부족합니다.";
                case "-31205": return "취소/거부된 문서는 FAX 전송이 불가능합니다.";
                case "-31207": return "역발행 문서는 FAX 기능을 지원하지 않습니다.";
                case "-10146": return "파일은 최대 10개까지 전송하실 수 있습니다.";
                case "-31210": return "팩스전송을 위한 파일생성에 실패하였습니다.";
                case "-31211": return "팩스전송을 위한 파일을 찾을 수 없습니다.";
                case "-31214": return "90일이 경과된 건은 재전송하실 수 없습니다.";
                #endregion
                default:
                    return "";
            }
        }

        /// <summary>
        /// 코드에 따른 오류 메시지 반환
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        private string Msg_result(string msg)
        {
            switch (msg)
            {
                case "100":
                    return "과금실패";
                case "101":
                    return "변환실패";
                case "102":
                    return "변환실패 (30분 타임아웃)";
                case "801":
                    return "부분완료";
                case "802":
                    return "완료";
                case "803":
                    return "통화중 (재전송시도)";
                case "804":
                    return "잘못된 수신번호";
                case "805":
                    return "응답없음";
                case "806":
                    return "수화기들음";
                case "807":
                    return "수신거부";
                case "808":
                    return "알수없는 오류";
                case "809":
                    return "콜 혼잡";
                case "810":
                    return "파일변환 오류";
                case "811":
                    return "전송데이터 없음";
                case "812":
                    return "파일저장 오류";
                case "813":
                    return "입력항목 오류";
                case "814":
                    return "소켓통신 오류";
                default:
                    return "알수없는 오류";
            }
        }
    }

    class Barobill_TI
    {
        private string CERTKEY = "BC5F164E-6410-44FF-BADF-25732E850D36";    //인증키
        private string CorpNum = "4088188534";                //바로빌 회원 사업자번호 ('-' 제외, 10자리)
        private string SenderID = "gloriabook";               //연계사업자 담당자 아이디
        BaroService_TISoapClient tiSoapClient = new BaroService_TISoapClient();

        /// <summary>
        /// 회원사 회원가입여부 확인
        /// </summary>
        /// <param name="CheckCorpNum">회원사명</param>
        /// <returns>0:가입되지않음<br>1:가입되어있음</br><br>음수:실패</br></returns>
        private int CheckCorpIsMember(string CheckCorpNum)
        {
            return tiSoapClient.CheckCorpIsMember(this.CERTKEY, this.CorpNum, CheckCorpNum);
        }
    }

    /// <summary>
    /// ftp 관련 클래스
    /// </summary>
    class FTP
    {
        #region 
        public delegate void ExceptionEventHandler(string LocationID, Exception ex);
        public event ExceptionEventHandler ExceptionEvent;

        public Exception LastException = null;

        public bool IsConnected { get; set; }

        private string ipAddr = string.Empty;
        private string Port = string.Empty;
        private string userId = string.Empty;
        private string Pwd = string.Empty;

        public FTP() { }

        public bool ConnectToServer(string ip, string port, string userid, string pwd)
        {
            this.IsConnected = false;

            this.ipAddr = ip;
            this.Port = port;
            this.userId = userid;
            this.Pwd = pwd;

            string url = string.Format(@"FTP://{0}:{1}/", this.ipAddr, this.Port);

            try
            {
                FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(url);
                ftpRequest.Credentials = new NetworkCredential(userId, Pwd);
                ftpRequest.KeepAlive = false;
                ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;
                ftpRequest.UseBinary = true;    // 파일 깨짐 방지
                ftpRequest.UsePassive = true;   // Passive 모드 설정

                using (ftpRequest.GetResponse()) { }
                this.IsConnected = true;
            }
            catch (Exception ex)
            {
                this.LastException = ex;
                System.Reflection.MemberInfo info = System.Reflection.MethodInfo.GetCurrentMethod();
                string id = string.Format("{0}.{1}", info.ReflectedType.Name, info.Name);

                if (this.ExceptionEvent != null) { this.ExceptionEvent(id, ex); }
                return false;
            }
            return true;
        }
        public bool UpLoad(string folder, string filename)
        {
            return upload(folder, filename);
        }
        public bool DownLoad(string localFullPathFile, string serverFullPathFile)
        {
            return download(localFullPathFile, serverFullPathFile);
        }
        public List<string> GetFIleList(string serverFolder)
        {
            return getFileList(serverFolder);
        }
        private bool upload(string folder, string filename)
        {
            try
            {
                makeDir(folder);

                FileInfo fileinf = new FileInfo(filename);

                folder = folder.Replace('\\', '/');
                filename = filename.Replace('\\', '/');

                string url = string.Format(@"FTP://{0}:{1}/{2}{3}", ipAddr, Port, folder, fileinf.Name);

                FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(url);
                ftpRequest.Credentials = new NetworkCredential(userId, Pwd);
                ftpRequest.KeepAlive = false;
                ftpRequest.UseBinary = false;
                ftpRequest.UsePassive = true;

                ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
                ftpRequest.ContentLength = fileinf.Length;

                int buffLength = 2048;
                byte[] buff = new byte[buffLength];
                int contentLen;

                using (FileStream fs = fileinf.OpenRead())
                {
                    using (Stream strm = ftpRequest.GetRequestStream())
                    {
                        contentLen = fs.Read(buff, 0, buffLength);
                        while (contentLen != 0)
                        {
                            strm.Write(buff, 0, contentLen);
                            contentLen = fs.Read(buff, 0, buffLength);
                        }
                    }
                    fs.Flush();
                    fs.Close();
                }
                if (buff != null)
                {
                    Array.Clear(buff, 0, buffLength);
                    buff = null;
                }
            }
            catch (Exception ex)
            {
                UTIL.MsgE(ex.ToString());
                this.LastException = ex;
                System.Reflection.MemberInfo info = System.Reflection.MethodInfo.GetCurrentMethod();
                string id = string.Format("{0}.{1}", info.ReflectedType.Name, info.Name);

                if (this.ExceptionEvent != null) { this.ExceptionEvent(id, ex); }
                return false;
            }
            return true;
        }
        private bool download(string localFullPathFile, string serverFullPathFile)
        {
            try
            {
                checkDir(localFullPathFile);

                string url = string.Format(@"FTP://{0}:{1}/{2}", ipAddr, Port, serverFullPathFile);
                FtpWebRequest ftp = (FtpWebRequest)WebRequest.Create(url);

                ftp.Credentials = new NetworkCredential(userId, Pwd);
                ftp.KeepAlive = false;
                ftp.UseBinary = true;
                ftp.UsePassive = false;

                using (FtpWebResponse response = (FtpWebResponse)ftp.GetResponse())
                {
                    using (FileStream output = new FileStream(localFullPathFile, FileMode.Create, FileAccess.Write))
                    {
                        using (Stream ftpStream = response.GetResponseStream())
                        {
                            int bufferSize = 2048;
                            int readCount;
                            byte[] buffer = new byte[bufferSize];

                            readCount = ftpStream.Read(buffer, 0, bufferSize);
                            while (readCount > 0)
                            {
                                output.Write(buffer, 0, readCount);
                                readCount = ftpStream.Read(buffer, 0, bufferSize);
                            }

                            ftpStream.Close();
                            output.Close();

                            if (buffer != null)
                            {
                                Array.Clear(buffer, 0, buffer.Length);
                                buffer = null;
                            }
                        }
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                UTIL.MsgE(ex.ToString());
                this.LastException = ex;

                if (serverFullPathFile.Contains(@"\ZOOM\"))
                    return false;
                System.Reflection.MemberInfo info = System.Reflection.MethodInfo.GetCurrentMethod();
                string id = string.Format("{0}.{1}", info.ReflectedType.Name, info.Name);
                if (this.ExceptionEvent != null)
                    this.ExceptionEvent(id, ex);
                return false;
            }
        }
        private List<string> getFileList(string serverFolder)
        {
            List<string> resultList = new List<string>();
            StringBuilder result = new StringBuilder();

            try
            {
                string url = string.Format(@"FTP://{0}:{1}/{2}", this.ipAddr, this.Port, serverFolder);

                FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(url);
                ftpRequest.Credentials = new NetworkCredential(userId, Pwd);
                ftpRequest.KeepAlive = false;
                ftpRequest.UseBinary = false;
                ftpRequest.UsePassive = false;

                ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;

                using (WebResponse response = ftpRequest.GetResponse())
                {
                    StreamReader reader = new StreamReader(response.GetResponseStream());

                    string line = reader.ReadLine();
                    while (line != null)
                    {
                        result.Append(line);
                        result.Append("\n");
                        line = reader.ReadLine();
                    }
                    result.Remove(result.ToString().LastIndexOf('\n'), 1);

                    if (reader != null) reader.Close();

                    foreach (string file in result.ToString().Split('\n'))
                    {
                        resultList.Add(file);
                    }
                }
                return resultList;
            }
            catch (Exception ex)
            {
                this.LastException = ex;

                System.Reflection.MemberInfo info =
                    System.Reflection.MethodInfo.GetCurrentMethod();
                string id = string.Format("{0}.{1}", info.ReflectedType.Name, info.Name);

                if (this.ExceptionEvent != null)
                    this.ExceptionEvent(id, ex);

                return resultList;
            }
        }
        private void makeDir(string dirName)
        {
            string[] arrDir = dirName.Split('\\');
            string currentDir = string.Empty;

            try
            {
                foreach (string tmpFolder in arrDir)
                {
                    try
                    {
                        if (tmpFolder == string.Empty) continue;

                        currentDir += @"/" + tmpFolder;

                        string url = string.Format(@"FTP://{0}:{1}/{2}", this.ipAddr, this.Port, currentDir);
                        FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(url);
                        ftpRequest.Credentials = new NetworkCredential(userId, Pwd);
                        ftpRequest.Method = WebRequestMethods.Ftp.MakeDirectory;
                        ftpRequest.KeepAlive = false;
                        ftpRequest.UsePassive = true;

                        FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse();
                        response.Close();
                    }
                    catch { }
                }
            }
            catch (Exception ex)
            {
                this.LastException = ex;
                System.Reflection.MemberInfo info = System.Reflection.MethodInfo.GetCurrentMethod();
                string id = string.Format("{0}.{1}", info.ReflectedType.Name, info.Name);

                if (this.ExceptionEvent != null) { this.ExceptionEvent(id, ex); }
            }
        }
        private void checkDir(string localFullPathFile)
        {
            FileInfo finfo = new FileInfo(localFullPathFile);
            if (!finfo.Exists)
            {
                DirectoryInfo dInfo = new DirectoryInfo(finfo.DirectoryName);
                if (!dInfo.Exists)
                {
                    dInfo.Create();
                }
            }
        }
        #endregion
    }
    public delegate void FTPDownloadTotalSizeHandle(long totalSize);
    public delegate void FTPDownloadReceivedSizeHandle(int RcvSize);

    /// <summary>
    /// 텍스트 관련 함수.
    /// </summary>
    class String_Text
    {
        /// <summary>
        /// 컴퓨터에 설치된 폰트를 불러옴.
        /// </summary>
        /// <returns></returns>
        public string[] callMyFont()
        {
            List<string> resultList = new List<string>();
            CultureInfo oldCulture = Thread.CurrentThread.CurrentCulture;
            try
            {
                Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfoByIetfLanguageTag("en-US");
                InstalledFontCollection installedFontCollection = new InstalledFontCollection();

                foreach (FontFamily font in installedFontCollection.Families)
                    resultList.Add(font.Name);
            }
            finally
            {
                Thread.CurrentThread.CurrentCulture = oldCulture;
            }
            return resultList.ToArray();
        }

        public string made_Ori_marc(RichTextBox rich)
        {
            string text = rich.Text;
            return madeOrimarc(text);
        }
        public string made_Ori_marc(string rich)
        {
            return madeOrimarc(rich);
        }

        /// <summary>
        /// DVD CD LP 구분짓는 함수
        /// </summary>
        /// <param name="rich"></param>
        /// <param name="MarcType">false일 경우 DVD CD LP</param>
        /// <returns></returns>
        public string made_Ori_marc(string rich, bool MarcType)
        {
            return madeOrimarc(rich, "ANSI", MarcType);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="rich"></param>
        /// <param name="EncodingType">ANSI, UTF-8, UniCode</param>
        /// <returns></returns>
        public string made_Ori_marc(string rich, string EncodingType)
        {
            return madeOrimarc(rich, EncodingType);
        }

        /// <summary>
        /// 한줄짜리 마크데이터로 만들어주는 함수
        /// </summary>
        /// <param name="rich">데이터가 담긴 텍스트박스</param>
        /// <returns>한줄짜리 마크데이터</returns>
        private string madeOrimarc(string rich, string EncodingType = "UniCode", bool MarcType = true)
        {
            string result = string.Empty;

            string 디렉토리 = string.Empty;
            string 가변길이 = string.Empty;
            string text = rich.Replace("\t", "");
            // text = text.Replace("\\", "￦");
            List<string> array_text = text.Split('\n').ToList();
            array_text.RemoveAll(x => x == "");
            // num+count+total = 디렉토리
            List<string> num = new List<string>();
            //List<string> count = new List<string>();
            //List<string> total = new List<string>();

            List<int> tCount = new List<int>();
            List<int> tTotal = new List<int>();
            int tLength = 0;
            int tUp = 0;
            int tDown = 0;
            for (int a = 0; a < array_text.Count; a++)
            {
                // if (array_text[a] == "") continue;

                num.Add(array_text[a].Substring(0, 3));

                if (array_text[a][5] == '▼')
                {
                    array_text[a] = array_text[a].Remove(0, 3);
                }
                else
                {
                    array_text[a] = array_text[a].Remove(0, 5);
                }

                가변길이 += array_text[a] + "\n";
                int textLength = 0;
                if (EncodingType == "UTF-8")
                {
                    textLength = Encoding.UTF8.GetBytes(array_text[a]).Length
                    - WordCheck(array_text[a], "▲")
                    - WordCheck(array_text[a], "▼");
                }
                else if (EncodingType == "UniCode")
                {
                    textLength = Encoding.Unicode.GetBytes(array_text[a]).Length
                    - WordCheck(array_text[a], "▲")
                    - WordCheck(array_text[a], "▼");
                }
                else
                {  // ANSI
                    textLength = Encoding.Default.GetBytes(array_text[a]).Length
                    - WordCheck(array_text[a], "▲")
                    - WordCheck(array_text[a], "▼");
                }

                //count.Add(insert_Zero(textLength, 4));
                tCount.Add(textLength);
            }

            for (int a = 0; a < array_text.Count; a++)
            {
                if (a == 0)
                { //total.Add("0");
                    tTotal.Add(0);
                }
                else
                {
                    // total.Add(total[a - 1] + count[a - 1]);
                    tTotal.Add(tTotal[a - 1] + tCount[a - 1]);
                }
                //else if (a == 1)
                //{
                //    int b = Convert.ToInt32(total[total.Count - 1]);
                //    total.Add(b.ToString());
                //}
                //else if (a > 1)
                //{
                //    int b = Convert.ToInt32(total[total.Count - 1]);
                //    int c = 0;
                //    if (EncodingType == "UTF-8") c = Convert.ToInt32(Encoding.UTF8.GetBytes(array_text[a - 2]).Length.ToString()) - WordCheck(array_text[a - 2], "▲") - WordCheck(array_text[a - 2], "▼");
                //    else if (EncodingType == "UniCode") c = Convert.ToInt32(Encoding.Unicode.GetBytes(array_text[a - 2]).Length.ToString()) - WordCheck(array_text[a - 2], "▲") - WordCheck(array_text[a - 2], "▼");
                //    else c = Convert.ToInt32(Encoding.Default.GetBytes(array_text[a - 2]).Length.ToString()) - WordCheck(array_text[a - 2], "▲") - WordCheck(array_text[a - 2], "▼");
                //    int res = b + c;
                //    total.Add(res.ToString());

            }

            string[] str_num = num.ToArray();
            for (int a = 0; a < str_num.Length; a++)
            {
                //count[a] = count[a].PadLeft(4, '0');
                // if (count[a].Length == 3) { count[a] = count[a].Insert(0, "0"); }
                // else if (count[a].Length == 2) { count[a] = count[a].Insert(0, "00"); }
                // else if (count[a].Length == 1) { count[a] = count[a].Insert(0, "000"); }

                //total[a] = total[a].PadLeft(5, '0');
                // if (total[a].Length == 4) { total[a] = total[a].Insert(0, "0"); }
                // else if (total[a].Length == 3) { total[a] = total[a].Insert(0, "00"); }
                // else if (total[a].Length == 2) { total[a] = total[a].Insert(0, "000"); }
                // else if (total[a].Length == 1) { total[a] = total[a].Insert(0, "0000"); }
                // 디렉토리 += str_num[a] + count[a] + total[a] + "\n";
                디렉토리 += str_num[a] + tCount[a].ToString().PadLeft(4, '0') + tTotal[a].ToString().PadLeft(5, '0');
            }

            string[] 리더부 = { "00000","n", "a", "m", " ",
                                " ", "2", "2", "00000", " ",
                                "k", " ", "4", "5", "0",
                                "0" };
            if (!MarcType) 리더부[2] = "g";
            디렉토리 += "";
            // 디렉토리 = 디렉토리.Replace("\n", "");

            가변길이 += "";
            가변길이 = 가변길이.Replace("\n", "");

            string dp = 가변길이 + 디렉토리;
            int recode = 0;
            if (EncodingType == "UTF-8") recode = Encoding.UTF8.GetBytes(dp).Length - WordCheck(dp, "▲") - WordCheck(dp, "▼") - WordCheck(dp, "↔");
            else if (EncodingType == "UniCode") recode = Encoding.Unicode.GetBytes(dp).Length - WordCheck(dp, "▲") - WordCheck(dp, "▼") - WordCheck(dp, "↔");
            else recode = Encoding.Default.GetBytes(dp).Length - WordCheck(dp, "▲") - WordCheck(dp, "▼") - WordCheck(dp, "↔");


            리더부[0] = insert_Zero(recode + 24, 5);

            int data_addr = 24 + Encoding.Default.GetBytes(디렉토리).Length - WordCheck(디렉토리, "▲");
            리더부[8] = insert_Zero(data_addr, 5);

            for (int a = 0; a < 리더부.Length; a++)
            {
                result += 리더부[a];
            }

            result += 디렉토리 + 가변길이;
            result = result.Replace("▲", "");
            result = result.Replace("▼", "");

            return result;
        }
        #region made_Ori_marc_Sub
        int WordCheck(string String, string Word)
        {
            string[] StringArray = String.Split(new string[] { Word }, StringSplitOptions.None);
            return StringArray.Length - 1;
        }
        string insert_Zero(int value, int count)
        {
            string result = string.Empty;
            switch (count)
            {
                case 5:
                    if (value < 10) { result = "0000"; }
                    else if (value < 100) { result = "000"; }
                    else if (value < 1000) { result = "00"; }
                    else if (value < 10000) { result = "0"; }
                    break;
                case 6:
                    if (value < 10) { result = "000"; }
                    else if (value < 100) { result = "00"; }
                    else if (value < 1000) { result = "0"; }
                    break;
                default:
                    break;
            }
            result += value.ToString();
            result = result.PadLeft(count, '0');
            return result;
        }
        #endregion


        /// <summary>
        /// 추가하고 싶은 태그를 뷰형태의 마크에 추가하는 함수.
        /// </summary>
        /// <param name="Tag">추가할 태그 (태그명\t지시기호\t태그내용)</param>
        /// <param name="TypeView">뷰형태의 마크</param>
        /// <returns></returns>
        public string AddTagInMarc(string Tag, string TypeView)
        {
            if (Tag.Length < 3) return "";

            int TargetTagNum = Convert.ToInt32(Tag.Substring(0, 3));

            string[] SplitView = TypeView.Split('\n');
            List<string> View = new List<string>(SplitView);

            int ViewCount = 0;
            foreach (string LineMarc in View)
            {
                string LineTag = LineMarc.Substring(0, 3);
                int TagNum = Convert.ToInt32(LineTag);

                if (TargetTagNum < TagNum)
                {
                    View.Insert(ViewCount, Tag);
                    break;
                }
                ViewCount++;
            }
            return string.Join("\n", View);
        }
        /// <summary>
        /// 추가하고 싶은 태그를 뷰형태의 마크에 추가하는 함수.
        /// </summary>
        /// <param name="pAddTag">추가할 태그 (태그명\t지시기호\t태그내용)</param>
        /// <param name="pTargetData">뷰형태의 마크</param>
        /// <returns></returns>
        public string AddTagInMarc(int pTargetTagNum, string pAddTag, string pTargetData)//TagTarget Num 을 찾아서 있을경우는 해당 Tag 데이터를 전송, 없을경우는 신규로 해야함.
        {

            if (pAddTag.Length < 3) return "";
            string tRet = pTargetData;
            // ex ) 020 : ~~~ 에 XXXX 내용줄 뒤에 추가

            return tRet;
        }
        public int SearchTarget()
        {
            int tRet = 0;
            return tRet;
        }
        /// <summary>
        /// 지정된 태그 변경
        /// </summary>
        /// <param name="Tag">변경할 태그 ex)245a</param>
        /// <param name="ChangeContent">변결할 태그에 들어갈 내용</param>
        /// <param name="TypeView">뷰마크</param>
        /// <returns></returns>
        public string ChangeTagInMarc(string Tag, string ChangeContent, string TypeView)
        {
            if (Tag.Length < 2) return TypeView;

            string TargetTagNum = Tag.Substring(0, 3);
            string TargetTag = Tag.Replace(TargetTagNum, "");

            List<string> SplitView = TypeView.Split('\n').ToList();
            for (int a = 0; a < SplitView.Count; a++)
            {
                if (SplitView[a].Length < 2) continue;

                if (!SplitView[a].StartsWith(TargetTagNum)) continue;

                int startIdx = SplitView[a].IndexOf("▼" + TargetTag);
                // if (startIdx < 0) break;
                if (startIdx < 0)
                {// 해당 태그 알파벳이 없어서 새로 추가해야하는 경우
                    if (TargetTagNum == "020")
                    {
                        int[] tFindAlpha = new int[] { Convert.ToInt32('c'), Convert.ToInt32('g'), Convert.ToInt32('a') };// c=> g => a 순서로 검색해서 붙여준다.
                        int tChar = Convert.ToInt32(TargetTag[0]);
                        for (int i = 0; i < tFindAlpha.Length; i++)
                        {
                            char tSearchChar = Convert.ToChar(tFindAlpha[i]);//020c의 경우 a g 다음에 붙어야한다.
                            startIdx = SplitView[a].IndexOf("▼" + tSearchChar.ToString());
                            if (startIdx != -1)
                            {
                                int tEndIDX = SplitView[a].IndexOf("▼", startIdx + 1);
                                List<string> tFindList = SplitView.FindAll(x => x.Contains(TargetTagNum)).FindAll(x => x.Contains(ChangeContent));
                                if (tFindList.Count == 0)
                                {
                                    if (tEndIDX < 0)
                                    {
                                        tEndIDX = SplitView[a].IndexOf("▲", startIdx);
                                        string Target = SplitView[a].Substring(startIdx, tEndIDX - startIdx);
                                        SplitView[a] = SplitView[a].Replace(Target, Target + ChangeContent);
                                    }
                                    else
                                    {
                                        SplitView[a] = SplitView[a].Insert(tEndIDX, ChangeContent);
                                    }
                                }
                                break;
                            }
                        }
                    }
                    else
                    {
                        int tChar = Convert.ToInt32(TargetTag[0]);
                        for (int i = tChar; i > 96; i--)
                        {
                            char tSearchChar = Convert.ToChar(i);//020c의 경우 a g 다음에 붙어야한다.
                            startIdx = SplitView[a].IndexOf("▼" + tSearchChar.ToString());
                            if (startIdx != -1)
                            {
                                int tEndIDX = SplitView[a].IndexOf("▼", startIdx + 1);
                                List<string> tFindList = SplitView.FindAll(x => x.Contains(TargetTagNum)).FindAll(x => x.Contains(ChangeContent));
                                if (tFindList.Count == 0)
                                {
                                    if (tEndIDX < 0)
                                    {
                                        tEndIDX = SplitView[a].IndexOf("▲", startIdx);
                                        string Target = SplitView[a].Substring(startIdx, tEndIDX - startIdx);
                                        SplitView[a] = SplitView[a].Replace(Target, Target + ChangeContent);
                                    }
                                    else
                                    {
                                        SplitView[a] = SplitView[a].Insert(tEndIDX, ChangeContent);
                                    }
                                }
                                break;
                            }
                        }
                    }
                }
                else
                {// 기존 태그 변경
                    int endIdx = SplitView[a].IndexOf("▼", startIdx + 1);
                    if (endIdx < 0) endIdx = SplitView[a].IndexOf("▲", startIdx);

                    string Target = SplitView[a].Substring(startIdx, endIdx - startIdx);
                    SplitView[a] = SplitView[a].Replace(Target, ChangeContent);
                }
            }
            return String.Join("\n", SplitView);
        }

        /// <summary>
        /// 해당하는 태그 모두 삭제
        /// </summary>
        /// <param name="ViewMarc"></param>
        /// <param name="RemoveNumber"></param>
        /// <returns></returns>
        public string RemoveTagNumber(string ViewMarc, string RemoveNumber)
        {
            if (ViewMarc.Length < 3) return "";

            List<string> SplitMarc = new List<string>(ViewMarc.Split('\n'));

            int idx = -1, count = 0;
            for (int a = 0; a < SplitMarc.Count; a++)
            {
                if (SplitMarc[a].StartsWith(RemoveNumber))
                {
                    if (idx < 0)
                        idx = a;
                    count++;
                }
            }

            if (idx >= 0)
                SplitMarc.RemoveRange(idx, count);

            return String.Join("\n", SplitMarc);
        }

        /// <summary>
        /// 색상 변경함수(richTextBox에만 적용)
        /// </summary>
        /// <param name="strTarget"></param>
        public void Color_change(string strTarget, RichTextBox rich)
        {
            Regex regex = new Regex(strTarget);
            MatchCollection mc = regex.Matches(rich.Text);
            rich.Select(0, rich.Text.Length);
            rich.SelectionBackColor = Color.LightGray;

            int ICursorPosition = rich.SelectionStart;
            foreach (Match m in mc)
            {
                int istartidx = m.Index;
                int istopidx = m.Length + 1;
                int istopidx1 = m.Length;

                if (strTarget == "▼" || strTarget == "▲") { rich.Select(istartidx, istopidx); }
                else { rich.Select(istartidx, istopidx1); }

                if (strTarget == "▼") { rich.SelectionColor = Color.Blue; }
                else if (strTarget == "▲") { rich.SelectionColor = Color.Red; }
                else { rich.SelectionBackColor = Color.Orange; }     // TODO: 색상 변경될수 있음.

                rich.SelectionStart = ICursorPosition;
                if (strTarget == "▼" || strTarget == "▲") { rich.SelectionColor = Color.Black; }
                else { rich.SelectionBackColor = Color.Empty; }
            }
        }

        /// <summary>
        /// 원 마크 데이터에서 태그 추출하는 함수
        /// </summary>
        /// <param name="marc">마크 데이터</param>
        /// <param name="search">추출할 함수(배열)</param>
        /// <returns></returns>
        public string[] Take_Tag(string marc, string[] search, bool pSearchTag = false)
        {
            string[] ary = marc.Split(''); //0x1E
            string[] tag = res_dir(ary[0].Substring(24));
            (string[] jisi, string[] mrc) = jisi_Symbol(tag, ary);

            string[] s_tag = new string[search.Length];
            string[] scan = new string[search.Length];
            try
            {
                for (int a = 0; a < search.Length; a++)
                {
                    s_tag[a] = search[a].Substring(0, 3);
                    scan[a] = "" + search[a].Substring(3);
                }
            }
            catch { }

            string[] result = new string[search.Length];
            string memo = string.Empty;

            for (int a = 0; a < tag.Length; a++)
            {
                for (int b = 0; b < s_tag.Length; b++)
                {
                    if (tag[a] == s_tag[b])
                    {
                        string tmp = mrc[a];
                        int start = tmp.IndexOf(scan[b]);

                        if (start < 0)
                        {
                            int tag_num = Convert.ToInt32(s_tag[b]);
                            if (tag_num < 10)
                                result[b] = tmp;
                            else
                                result[b] = "";
                        }
                        else
                        {
                            //start += 2;
                            //int end = tmp.IndexOf("", start);
                            //if (memo == result[b])
                            //    break;

                            //if (end < 0)
                            //    result[b] = tmp.Substring(start);
                            //else
                            //    result[b] = tmp.Substring(start, end - start);
                            //memo = result[b];
                            start += 2;
                            int end = -1;
                            if (tmp.Length > 1) end = tmp.IndexOf("", start);
                            if (memo == result[b])
                                break;

                            if (end < 0)
                            {
                                if (!pSearchTag) result[b] = tmp.Substring(start);
                                else
                                {
                                    if (tmp.Length > 1) result[b] = tmp.Substring(start);
                                    else result[b] = "태그 안에 데이터가 없습니다.";
                                }
                            }
                            else
                                result[b] = tmp.Substring(start, end - start);
                            memo = result[b];
                        }
                    }
                }
            }

            for (int a = 0; a < result.Length; a++)
            {
                if (result[a] == null)
                {
                    result[a] = "";
                }
            }
            return result;
        }

        /// <summary>
        /// 뷰 마크 데이터에서 태그를 검색하되, 조건에 적용된 마크가 있을 경우에 리턴이 가능.
        /// </summary>
        /// <param name="marc">뷰마크 데이터</param>
        /// <param name="search">추출할 태그 (ex. 245a)</param>
        /// <param name="search">조건 태그 (ex. 245b)</param>
        /// <returns></returns>
        public string TakeTag_ConditionContent(string ViewMarc, string SearchTag, string Condition)
        {
            string[] ary = ViewMarc.Split('▲');

            string SearchTagNum = SearchTag.Substring(0, 3);
            string SearchTagAlpha = "▼" + SearchTag.Substring(3);

            string ConditionTagNum = Condition.Substring(0, 3);
            bool isCondition = false;
            string ConditionTagAlpha = "▼" + Condition.Substring(3);

            foreach (string item in ary)
            {
                string[] TagArray = item.Split('\t');
                if (item.StartsWith(ConditionTagNum))
                {
                    foreach (string Condi in TagArray)
                    {
                        if (Condi.Contains(ConditionTagAlpha))
                            isCondition = true;
                    }
                }
            }

            if (isCondition)
                return "";

            string result = "";
            foreach (string item in ary)
            {
                string[] TagArray = item.Split('\t');
                if (item.StartsWith(SearchTagNum))
                {
                    foreach (string SearchItem in TagArray)
                    {
                        if (SearchItem.Contains(ConditionTagAlpha))
                            result = GetMiddelString(SearchItem, SearchTagAlpha, "▼").Replace("▲", "");
                    }
                }
            }
            return result;
        }

        public string TakeTag_FilterJisi(string marc, string search, string searchJisi)
        {
            string[] ary = marc.Split('');
            string[] tag = res_dir(ary[0].Substring(24));
            (string[] jisi, string[] mrc) = jisi_Symbol(tag, ary);

            string s_tag = "";
            string scan = "";
            try
            {
                s_tag = search.Substring(0, 3);
                scan = "" + search.Substring(3);
            }
            catch { }

            string result = "";

            for (int a = 0; a < tag.Length; a++)
            {
                if (tag[a] == s_tag)
                {
                    string tmp = mrc[a];
                    int start = tmp.IndexOf(scan);

                    if (jisi[a] != searchJisi)
                    {
                        break;
                    }

                    if (start < 0)
                    {
                        result = tmp;
                    }
                    else
                    {
                        start += 2;
                        int end = tmp.IndexOf("", start);
                        if (end < 0)
                            result = tmp.Substring(start);
                        else
                            result = tmp.Substring(start, end - start);
                    }
                }
            }
            if (result == null)
                result = "";

            return result;
        }
        #region Take_Tag_Sub
        string[] res_dir(string dir)
        {
            List<string> tmp = new List<string>();
            for (int a = 0; a < dir.Length; a++)
            {
                if (a % 12 == 0)
                    tmp.Add(dir.Substring(a, 3));
            }
            return tmp.ToArray();
        }

        (string[], string[]) jisi_Symbol(string[] dir, string[] marc)
        {
            List<string> res = new List<string>();
            List<string> tmp = new List<string>();

            for (int a = 0; a < dir.Length; a++)
            {
                if (dir[a].Length < 1)
                    break;

                if (marc[a + 1].Contains(""))
                {
                    res.Add(marc[a + 1].Substring(0, 2));
                    tmp.Add(marc[a + 1].Substring(2));
                }
                else
                {
                    res.Add("");
                    tmp.Add(marc[a + 1]);
                }
            }
            return (res.ToArray(), tmp.ToArray());
        }
        #endregion

        /// <summary>
        /// 한줄짜리 마크를 보기 쉬운 형태로 변환
        /// </summary>
        /// <param name="Marc">한줄짜리 마크</param>
        /// <returns></returns>
        public string ConvertMarcType(string Marc, out string errmessage)
        {
            errmessage = string.Empty;
            if (Marc.Length < 3)
            {
                errmessage = "MARC 데이터길이가 너무 짧습니다.";
                return "";
            }

            string result = "";

            List<string> TagNum = new List<string>();   // 태그번호 저장용
            List<string> Field = new List<string>();    // 가변길이필드 저장용

            Marc = Marc.Replace("", "▼").Replace("", "▲");
            Marc = Marc.Replace(((char)0x1D).ToString(), "");
            Marc = Marc.Replace(((char)0x1E).ToString(), "");
            Marc = Marc.Replace(((char)0x1F).ToString(), "");

            int StartIdx = 0;

            // 리더부를 제외한 디렉토리, 가변길이필드 저장
            string[] data = Marc.Substring(24).Split(new char[] { '▲' }, StringSplitOptions.RemoveEmptyEntries);
            for (int a = 1; a < data.Length; a++)
            {
                TagNum.Add(data[0].Substring(StartIdx, 3));
                StartIdx += 12;
                Field.Add(data[a] + "▲");
            }

            // List에 들어간 데이터를 메모장에 출력
            for (int a = 0; a < TagNum.Count; a++)
            {
                string res = TagNum[a];
                if (Field[a].IndexOf("▲") == -1)
                    res += "\t  \t" + Field[a];
                else if (res.StartsWith("00")) { res += "\t  \t" + Field[a]; }
                else
                {
                    var fieldValue = Field[a].Trim();
                    bool isEmpty = false;
                    if (fieldValue.IndexOf("▼") != -1)
                    {
                        var dataArea = fieldValue.Substring(fieldValue.IndexOf("▼") + 1);
                        isEmpty = dataArea.ToString().isEmpty();
                    }
                    else
                    {
                        isEmpty = fieldValue.Replace("▲", "").Trim().isEmpty();
                    }
                    if (isEmpty) //no data
                    {
                        errmessage = (errmessage.isEmpty() == false ? "\n" : "") + "태그 " + TagNum[a] + " 에 데이터가 없습니다.";
                        Console.WriteLine("field length error");
                        res = string.Empty;
                    }
                    else
                    {
                        string temp = Field[a].Insert(2, "\t");
                        res += "\t" + temp;
                    }

                }
                if (res.isEmpty() == false)
                    result += res + "\n";
            }
            return result;
        }

        /// <summary>
        /// 텍스트박스 숫자만 입력받는 함수. KeyPress함수에 적용
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Only_Int(object sender, KeyPressEventArgs e)
        {
            if (!(char.IsDigit(e.KeyChar) || e.KeyChar == Convert.ToChar(Keys.Back)))
            {
                e.Handled = true;
            }
        }
        /// <summary>
        /// TextChanged이벤트 - 천단위 콤마찍어주기
        /// </summary>
        /// <param name="sender">object sender</param>
        /// <param name="e">EventArgs</param>
        public void Int_Comma(object sender, EventArgs e)
        {
            if (((TextBox)sender).Text != "")
            {
                string text;
                text = ((TextBox)sender).Text.Replace(",", "");
                ((TextBox)sender).Text = String.Format("{0:#,###}", Convert.ToInt32(text));
                ((TextBox)sender).SelectionStart = ((TextBox)sender).TextLength;
                ((TextBox)sender).SelectionLength = 0;
            }
        }
        /// <summary>
        /// 문자열 내에 한글이 들어가는지 체크
        /// </summary>
        /// <param name="value">대상 문자열</param>
        /// <returns>한글 포함시 true</returns>
        public bool isContainHangul(string value)
        {
            char[] charArr = value.ToCharArray();
            foreach (char c in charArr)
            {
                if (char.GetUnicodeCategory(c) == System.Globalization.UnicodeCategory.OtherLetter)
                    return true;

            }
            return false;
        }
        /// <summary>
        /// 대상 문자열안에 찾고 싶은 문자 찾기
        /// </summary>
        /// <param name="value">대상 문자열</param>
        /// <param name="chkString">찾고 싶은 문자</param>
        /// <returns>있을 경우 True반환</returns>
        public bool CheckString(string value, string chkString)
        {
            int index = value.IndexOf(chkString);
            if (index < 0)
                return false;

            return true;
        }
        /// <summary>
        /// 문자와 문자사이의 값 가져오기
        /// </summary>
        /// <param name="str">대상 문자열</param>
        /// <param name="begin">시작 문자열</param>
        /// <param name="end">마지막 문자열</param>
        /// <returns>문자 사이값</returns>
        public string GetMiddelString(string str, string begin, string end)
        {
            if (string.IsNullOrEmpty(str))
            {
                return "";
            }

            string result = "";
            if (str.IndexOf(begin) > -1)
            {
                str = str.Substring(str.IndexOf(begin) + begin.Length);
                if (str.IndexOf(end) > -1) result = str.Substring(0, str.IndexOf(end));
                else result = str;
            }
            return result;
        }

        public string RemoveWordInBracket(string Target)
        {
            string startBracket = "(";
            string endBracket = ")";

            Regex regex = new Regex("[" + startBracket + "][^" + startBracket + "]*[" + endBracket + "]");
            string result = regex.Replace(Target, string.Empty);

            return result;
        }
    }
    public class API
    {

        public string CheckString(string pText, string pStr)
        {
            string tRet = pText;
            Regex reg = new Regex(@"([\" + pStr + "]+)" + @"[가-힣]+");//+ @"([\>]+)");//new Regex(@"([\<]+)"+ @"[ㄱ-ㅎ가-힣]+"+@"([\>]+)");
            MatchCollection tMatch = reg.Matches(tRet);
            for (int i = 0; i < tMatch.Count; i++)
            {
                string tChangeText = String.Format("《{0}》", Regex.Replace(tMatch[i].Groups[0].ToString(), @"[^ㄱ-ㅎ가-힣]", ""));
                tRet = tRet.Remove(tMatch[i].Groups[0].Index, tMatch[i].Groups[0].Length + 1);
                tRet = tRet.Insert(tMatch[i].Groups[0].Index, tChangeText);
            }

            return tRet;
        }
        /// <summary>
        /// https://blog.aladin.co.kr/openapi 참고
        /// </summary>
        /// <param name="Query"></param>
        /// <param name="QueryType"></param>
        /// <param name="Param"></param>
        /// <returns></returns>
        public List<string> Aladin(string Query, string QueryType, string[] Param)
        {
            List<string> result = new List<string>();
            // 쿼리 생성
            string key = "ttbgloriabook1512001";
            string site = "http://www.aladin.co.kr/ttb/api/ItemSearch.aspx";
            string query = string.Format("{0}?query={1}&TTBKey={2}&output=xml&querytype={3}&MaxResults={4}",
                site, Query, key, QueryType, 30.ToString());

            // 쿼리를 입력인자로 WebRequest 개채 생성
            WebRequest request = WebRequest.Create(query);

            // WebRequest개체의 헤더에 인증키 포함시키기.
            // request.Headers.Add("Authorization", header);

            // WebResponse개체를 통해 서비스 요청.
            WebResponse response = request.GetResponse();

            // 결과문자열 확인
            Stream stream = response.GetResponseStream();
            StreamReader reader = new StreamReader(stream, Encoding.UTF8);
            String xml = reader.ReadToEnd();
            stream.Close();
            // xml형식을 json형식으로 변환
            XmlDocument doc = new XmlDocument();
            try
            {
                //Regex reg = new Regex(@"([\<]+)" + @"[가-힣]+");//+ @"([\>]+)");//new Regex(@"([\<]+)"+ @"[ㄱ-ㅎ가-힣]+"+@"([\>]+)");
                //MatchCollection tMatch = reg.Matches(xml);
                //for (int i = 0; i < tMatch.Count; i++)
                //{
                //    string tChangeText = String.Format("《{0}》", Regex.Replace(tMatch[i].Groups[0].ToString(), @"[^ㄱ-ㅎ가-힣]", ""));
                //    xml = xml.Remove(tMatch[i].Groups[0].Index, tMatch[i].Groups[0].Length + 1);
                //    xml = xml.Insert(tMatch[i].Groups[0].Index, tChangeText);
                //}

                //reg = new Regex(@"([\〈]+)" + @"[가-힣]+");// + @"([\>]+)");//new Regex(@"([\<]+)"+ @"[ㄱ-ㅎ가-힣]+"+@"([\>]+)");
                xml = CheckString(xml, "<");
                xml = CheckString(xml, "〈");
                doc.LoadXml(xml);
            }
            catch (Exception ex)
            {
                return result;
            }
            var json = JsonConvert.SerializeXmlNode(doc);

            // json형식 분석을 위해 JavaScriptSerializer 개체 생성
            JavaScriptSerializer js = new JavaScriptSerializer();

            // 런타임에 개체를 확인하여 사용할수 있는 dynamic을 이용해 역직렬화
            dynamic dob = js.Deserialize<dynamic>(json);

            // "object"내에 있는것을 얻어오기 위해 다시 dynamic변수에 참조
            dynamic docs = "";
            try
            {
                docs = dob["object"]["item"];
            }
            catch
            {
                return result;
            }
            int length = 0;
            int ID_length = Param.Length;

            // 검색 결과가 1개 이하일 경우, 오류가 발생하여 try/catch문 사용.
            try
            {
                // docs는 요소 컬렉션으로 object로 변환.
                object[] buf = docs;
                length = buf.Length;
            }
            catch
            {
                object buf = docs;
                length = 1;
            }
           // List<string> retval = new List<string>();
            for (int a = 0; a < length; a++)
            {
                List<string> tmp_data = new List<string>();
                for (int b = 0; b < ID_length; b++)
                {
                    if (length == 1)
                    {
                        tmp_data.Add(docs[Param[b]]);
                    }
                    else
                    {
                        tmp_data.Add(docs[a][Param[b]]);
                    }
                    result.Add(tmp_data[b].Replace("|", ""));
                    //result += tmp_data[b].Replace("|", "") + "|";
                }
                //result += "\n";
            }
            return result;
        }
        public string Naver(string Query, string QueryType, string[] Param)
        {
            string result = string.Empty;
            string json = string.Empty;
            // url 생성
            string url = string.Format("https://openapi.naver.com/v1/search/book.json?{0}={1}&display=30&start=1", QueryType, Query);

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

            request.Headers.Add("X-Naver-Client-Id", "wYr0JczCBoDopq1NKTyQ");   // 클라이언트 아이디
            request.Headers.Add("X-Naver-Client-Secret", "QHzeXadtO7");         // 클라이언트 시크릿
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            string status = response.StatusCode.ToString();
            if (status == "OK")
            {
                Stream stream = response.GetResponseStream();
                StreamReader reader = new StreamReader(stream, Encoding.UTF8);
                json = reader.ReadToEnd();
            }
            else
            {
                UTIL.MsgE(status);
                return "Error";
            }

            // json형식 분석을 위해 JavaScriptSerializer 개체 생성
            JavaScriptSerializer js = new JavaScriptSerializer();

            // 런타임에 개체를 확인하여 사용할수 있는 dynamic을 이용해 역직렬화
            dynamic dob = js.Deserialize<dynamic>(json);

            // "object"내에 있는것을 얻어오기 위해 다시 dynamic변수에 참조
            dynamic docs = "";
            try
            {
                // docs = dob["object"]["item"];
                docs = dob["items"];
            }
            catch
            {
                return "";
            }
            int length = 0;
            int ID_length = Param.Length;

            // 검색 결과가 1개 이하일 경우, 오류가 발생하여 try/catch문 사용.
            try
            {
                // docs는 요소 컬렉션으로 object로 변환.
                object[] buf = docs;
                length = buf.Length;
            }
            catch
            {
                object buf = docs;
                length = 1;
            }
            for (int a = 0; a < length; a++)
            {
                List<string> tmp_data = new List<string>();
                for (int b = 0; b < ID_length; b++)
                {
                    tmp_data.Add(docs[a][Param[b]]);
                    result += tmp_data[b] + "|";
                }
                result += "\n\t";
            }
            return result;
        }

        public string NationalLibraryOfKorea(string Qurey, string Type, string[] Param)
        {
            string result = "";

            string key = "a3f31e44f88abab47760f8ab90569095e436ffde8695fc029073ed0d3cc8bffb";
            // url 생성
            string url = "http://seoji.nl.go.kr/landingPage/SearchApi.do?result_style=xml&page_no=1&page_size=30&";
            string qurey = url + string.Format("cert_key={0}&{1}={2}", key, Type, Qurey);
            // 쿼리를 입력인자로 WebRequest 개체 생성
            WebRequest request = WebRequest.Create(qurey);

            // WebResponse개체를 통해 서비스 요청.
            WebResponse response = request.GetResponse();

            // 결과문자열 확인
            Stream stream = response.GetResponseStream();
            StreamReader reader = new StreamReader(stream, Encoding.UTF8);
            string xml = reader.ReadToEnd();
            stream.Close();

            // xml형식을 json형식으로 변환
            XmlDocument doc = new XmlDocument();
            try
            {
                xml = CheckString(xml, "<");
                xml = CheckString(xml, "〈");
                doc.LoadXml(xml);
            }
            catch { return ""; }
            var json = JsonConvert.SerializeXmlNode(doc);

            // json형식 분석을 위해 JavaScriptSerializer 개체 생성
            JavaScriptSerializer js = new JavaScriptSerializer();

            // 런타임에 개체를 확인하여 사용할 수 있는 dynamic을 이용해 역직렬화
            dynamic dob = js.Deserialize<dynamic>(json);

            // "object"내에 있는 것을 얻어오기 위해 다시 dynamic 변수에 참조
            dynamic docs = "";
            try
            {
                docs = dob["o"]["docs"]["e"];
            }
            catch
            {
                return "";
            }
            int length = 0;
            int ID_length = Param.Length;

            // 검색 결과가 1개 이하일 경우, 오류발생하여 try/catch문 사용.
            try
            {
                // docs는 요소 컬렉션으로 object로 변환.
                object[] buf = docs;
                length = buf.Length;
            }
            catch
            {
                object buf = docs;
                length = 1;
            }
            for (int a = 0; a < length; a++)
            {
                List<string> tmp_data = new List<string>();
                for (int b = 0; b < ID_length; b++)
                {
                    if (length == 1)
                    {
                        try
                        {
                            tmp_data.Add(docs[Param[b]]["#text"]);
                        }
                        catch (KeyNotFoundException e)
                        {
                            tmp_data.Add("");
                        }
                    }
                    else
                    {
                        try
                        {
                            tmp_data.Add(docs[a][Param[b]]["#text"]);
                        }
                        catch (KeyNotFoundException e)
                        {
                            tmp_data.Add("");
                        }
                    }

                    result += tmp_data[b].Replace("|", "") + "|";
                }
                result += "\n";
            }
            return result;
        }

        public string Daum(string Query, string Type, string[] Param)
        {
            string result = string.Empty;

            // url생성
            string url = "https://dapi.kakao.com/v3/search/book";
            string query = string.Format("{0}?query={1}&target={2}&size={3}", url, Query, Type, 30);
            WebRequest request = WebRequest.Create(query);

            string rKey = "e3935565b731a2a6f32880c90d76403a";
            string header = "KakaoAK " + rKey;

            request.Headers.Add("Authorization", header);

            WebResponse response = request.GetResponse();
            Stream stream = response.GetResponseStream();
            StreamReader reader = new StreamReader(stream, Encoding.UTF8);
            string json = reader.ReadToEnd();
            stream.Close();

            JavaScriptSerializer js = new JavaScriptSerializer();
            dynamic dob = js.Deserialize<dynamic>(json);
            dynamic docs = dob["documents"];
            object[] buf = docs;

            int length = buf.Length;
            int ID_length = Param.Length;

            for (int a = 0; a < length; a++)
            {
                List<object> tmp_data = new List<object>();
                for (int b = 0; b < ID_length; b++)
                {
                    if (Param[b] == "authors")
                    {
                        object[] tmp = docs[a][Param[b]];
                        string tmp_str = string.Empty;
                        for (int j = 0; j < tmp.Length; j++)
                        {
                            tmp_str += tmp[j];
                            if (j < tmp.Length - 1)
                            {
                                tmp_str += ", ";
                            }
                        }
                        tmp_data.Add(tmp_str);
                        result += tmp_data[b] + "|";
                        tmp_str = "";
                    }
                    else
                    {
                        tmp_data.Add(docs[a][Param[b]]);
                        result += tmp_data[b] + "|";
                    }
                }
                result += "\n";
            }
            return result;
        }
    }
    public class Skill_Search_Text
    {
        /// <summary>
        /// 검색용 박스 제작
        /// </summary>
        /// <param name="title">제목</param>
        /// <param name="promptText">내용</param>
        /// <param name="value">검색할 문자열</param>
        /// <returns></returns>
        public DialogResult InputBox(string title, string promptText, ref string value)
        {
            Form form = new Form();
            Label label = new Label();
            TextBox textBox = new TextBox();
            Button btnOk = new Button();
            Button btnCancel = new Button();
            form.Text = title;
            label.Text = promptText;
            textBox.Text = value;
            btnOk.Text = "OK";
            btnCancel.Text = "Cancel";
            btnOk.DialogResult = DialogResult.OK;
            btnCancel.DialogResult = DialogResult.Cancel;
            label.SetBounds(9, 20, 372, 13);
            textBox.SetBounds(12, 36, 372, 20);
            btnOk.SetBounds(228, 72, 75, 23);
            btnCancel.SetBounds(309, 72, 75, 23);
            label.AutoSize = true;
            textBox.Anchor = textBox.Anchor | AnchorStyles.Right;
            btnOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
            btnCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
            form.ClientSize = new Size(396, 107);
            form.Controls.AddRange(new Control[] { label, textBox, btnOk, btnCancel });
            form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height);
            form.FormBorderStyle = FormBorderStyle.FixedDialog;
            form.StartPosition = FormStartPosition.CenterScreen;
            form.MinimizeBox = false;
            form.MaximizeBox = false;
            form.AcceptButton = btnOk;
            form.CancelButton = btnCancel;
            DialogResult dialogResult = form.ShowDialog();
            value = textBox.Text;
            return dialogResult;
        }
    }
    public class PrintLine
    {
        string num { get; set; }
        string count { get; set; }
        string list_name { get; set; }
        string book { get; set; }
        string price { get; set; }
        string comp { get; set; }
        string isbn { get; set; }

        int MaxX_title = 145;
        int MaxX = 125;

        /// <summary>
        /// 파라미터 순서대로 설정이 되어야함.
        /// </summary>
        /// <param name="num">목록번호</param>
        /// <param name="list_name">목록명</param>
        /// <param name="book">도서명</param>
        /// <param name="comp">출판사</param>
        /// <param name="isbn">해당 도서의 isbn</param>
        /// <param name="count">수량</param>
        /// <param name="price">가격</param>
        public PrintLine(string num, string list_name, string isbn, string book, string comp, string count, string price)
        {
            this.num = num;
            this.list_name = list_name;
            this.isbn = isbn;
            this.book = book;
            this.comp = comp;
            this.count = count;
            this.price = price;
        }
        /// <summary>
        /// 0:목록번호 1:목록명 2:isbn 3:도서명 4:출판사 5:수량 6:가격
        /// </summary>
        /// <param name="data">0:목록번호 1:목록명 2:isbn 3:도서명 4:출판사 5:수량 6:가격</param>
        public PrintLine(string[] data)
        {
            this.num = data[0];
            this.list_name = data[1];
            this.isbn = data[2];
            this.book = data[3];
            this.comp = data[4];
            this.count = data[5];
            this.price = data[6];
        }

        public void BnP_LinePrint(object sender, PrintPageEventArgs e)
        {
            Graphics g = e.Graphics;

            int xPos = 0;
            int yPos = 0;

            string list_tmp = count + "-" + list_name;

            Font title = new Font("굴림", 21, FontStyle.Bold);
            Font list = new Font("굴림", 16, FontStyle.Regular);
            Font book = new Font("굴림", 16, FontStyle.Regular);
            Font price = new Font("굴림", 16, FontStyle.Regular);

            RectangleF title_Area = new RectangleF(xPos, yPos, MaxX_title, 35);
            yPos += 35;
            RectangleF list_Area = new RectangleF(xPos, yPos, MaxX, 80);
            yPos += 75;
            RectangleF book_Area = new RectangleF(xPos, yPos, MaxX, 125);
            yPos += 125;
            RectangleF price_Area = new RectangleF(xPos, yPos, MaxX, 70);

            using (SolidBrush brush = new SolidBrush(Color.Black))
            {
                g.DrawString(this.num, title, brush, title_Area);
                g.DrawString(list_tmp, list, brush, list_Area);
                g.DrawString(this.book, book, brush, book_Area);
                g.DrawString(this.price, price, brush, price_Area);
            }
        }

        public void BnP_LinePrint_Edit(object sender, PrintPageEventArgs e)
        {

            Graphics g = e.Graphics;

            int xPos = 0;
            int yPos = 0;

            Pen p = new Pen(Color.Black);

            Font title = new Font("굴림", 21, FontStyle.Bold);
            Font count = new Font("굴림", 16, FontStyle.Bold);
            Font list = new Font("굴림", 14, FontStyle.Regular);
            Font book = new Font("굴림", 18, FontStyle.Regular);
            Font price_f = new Font("굴림", 14, FontStyle.Regular);

            RectangleF title_Area = new RectangleF(xPos, yPos, MaxX_title, 35);
            yPos += 30;
            RectangleF count_Area = new RectangleF(xPos, yPos, MaxX, 35);
            yPos += 25;
            RectangleF list_Area = new RectangleF(xPos, yPos, MaxX, 70);
            yPos += 65;
            RectangleF book_Area1 = new RectangleF(xPos, yPos, MaxX, 120);
            yPos += 115;
            RectangleF price_Area = new RectangleF(xPos, yPos, MaxX, 70);

            //g.DrawLine(p, MaxX, 0, MaxX, yPos);

            using (SolidBrush drawBrush = new SolidBrush(Color.Black))
            {
                g.DrawString(this.num, title, drawBrush, title_Area);
                g.DrawString(this.count + "권", count, drawBrush, count_Area);
                g.DrawString(this.list_name, list, drawBrush, list_Area);
                g.DrawString(this.book, book, drawBrush, book_Area1);
                g.DrawString(this.price, price_f, drawBrush, price_Area);
            }
        }

        public void New_LinePrint(object sender, PrintPageEventArgs e)
        {

            Graphics g = e.Graphics;

            int xPos = 0;
            int yPos = 0;

            Pen p = new Pen(Color.Black);

            Font list = new Font("굴림", 14, FontStyle.Regular);
            Font num = new Font("굴림", 18, FontStyle.Bold);
            Font book = new Font("굴림", 14, FontStyle.Bold);
            Font isbn = new Font("굴림", 11, FontStyle.Regular);

            RectangleF list_Area = new RectangleF(xPos, yPos, MaxX, 20);
            yPos += 20;
            RectangleF num_Area = new RectangleF(xPos, yPos, MaxX, 35);
            yPos += 30;
            g.DrawLine(p, xPos, yPos, MaxX, yPos);
            yPos += 5;
            RectangleF book_Area = new RectangleF(xPos, yPos, MaxX, 115);
            yPos += 115;
            RectangleF comp_Area = new RectangleF(xPos, yPos, MaxX, 20);
            yPos += 30;
            RectangleF num1_Area = new RectangleF(xPos, yPos, MaxX, 20);
            g.DrawLine(p, xPos, yPos, MaxX, yPos);
            yPos += 25;
            RectangleF isbn_Area = new RectangleF(xPos, yPos, MaxX, 20);
            yPos += 20;
            RectangleF price_Area = new RectangleF(xPos, yPos, MaxX, 20);

            using (SolidBrush drawBrush = new SolidBrush(Color.Black))
            {
                g.DrawString(this.list_name, list, drawBrush, list_Area);
                g.DrawString(this.num, num, drawBrush, num_Area);
                g.DrawString(this.count + "-" + this.book, book, drawBrush, book_Area);
                g.DrawString(this.comp, list, drawBrush, comp_Area);
                g.DrawString(this.list_name, book, drawBrush, num1_Area);
                g.DrawString(this.isbn, isbn, drawBrush, isbn_Area);
                g.DrawString(this.price, list, drawBrush, price_Area);
            }
        }
    }
    /// <summary>
    /// HangulJaso에서 한글자소에 대한 정보를 담음
    /// </summary>
    public struct HANGUL_INFO
    {
        /// <summary>
        /// 한글 여부(H, NH)
        /// </summary>
        public string isHangul;

        /// <summary>
        /// 분석 한글
        /// </summary>
        public char oriChar;

        /// <summary>
        /// 분리된 한글 (강 -> ㄱ ㅏ ㅇ)
        /// </summary>
        public char[] chars;
    }

    /// <summary>
    /// 한글 분석 클래스
    /// </summary>
    public sealed class HangulJaso
    {
        /// <summary>
        /// 초성 리스트
        /// </summary>
        public static readonly string HTable_ChoSung = "ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ";

        /// <summary>
        /// 중성 리스트
        /// </summary>
        public static readonly string HTable_JungSung = "ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ";

        /// <summary>
        /// 종성 리스트
        /// </summary>
        public static readonly string HTable_JongSung = "ㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ";

        private static readonly ushort m_UniCodeHangulBase = 0xAC00;

        private static readonly ushort m_UniCodeHangulLast = 0xD79F;

        /// <summary>
        /// 생성자
        /// </summary>
        public HangulJaso() { }

        /// <summary>
        /// 초성, 중성, 종성으로 이루어진 한글을 한글자의 한글로 만듬
        /// </summary>
        /// <param name="choSung">초성</param>
        /// <param name="jungSung">중성</param>
        /// <param name="jongSung">종성</param>
        /// <returns>합쳐진 글자</returns>
        /// <remarks>
        /// <para>초성, 중성, 종성으로 이루어진 한글을 한글자의 한글로 만든다.</para><example>
        /// <code>
        /// string choSung = "ㄱ", jungSung = "ㅏ", jongSung = "ㅇ";
        /// char hangul = MergeJaso(choSung, jungSung, jongSung);
        /// /결과 -> 강</code></example>
        /// </remarks>
        public static char MergeJaso(string choSung, string jungSung, string jongSung)
        {
            int ChoSungPos, JungSungPos, JongSungPos;
            int nUniCode;

            ChoSungPos = HTable_ChoSung.IndexOf(choSung);       // 초성 위치
            JungSungPos = HTable_JungSung.IndexOf(jungSung);    // 중성 위치
            JongSungPos = HTable_JongSung.IndexOf(jongSung);    // 종성 위치

            // 앞서 만들어 낸 계산식
            nUniCode = m_UniCodeHangulBase + (ChoSungPos * 21 + JungSungPos) * 28 + JongSungPos;

            // 코드값을 문자로 변환
            char temp = Convert.ToChar(nUniCode);

            return temp;
        }

        /// <summary>
        /// 한글자의 한글을 초성, 중성, 종성으로 나눈다.
        /// </summary>
        /// <param name="hanChar">한글</param>
        /// <returns>분리된 한글에 대한 정보</returns>
        /// <seealso cref="HANGUL_INFO"/>
        /// <remarks><para>한글자의 한글을 초성, 중성, 종성으로 나눈다.</para>
        /// <example><code>
        /// HANGUL_INFO hinfo = DevideJaso('강');
        /// // hinfo.isHangul -> "H"(한글)
        /// // hinfo.oriChar -> 강
        /// // hinfo.chars[0] -> ㄱ, hinfo.chars[1] -> ㅏ, hinfo.chars[2] -> ㅇ</code></example></remarks>
        public static HANGUL_INFO DevideJaso(char hanChar)
        {
            int ChoSung, JungSung, JongSung;    // 초성, 중성, 종성의 인덱스
            ushort temp = 0x0000;               // 임시로 코드값을 담을 변수

            HANGUL_INFO hi = new HANGUL_INFO();

            // Char을 16비트 부호없는 정수형 형태로 변환 - Unicode
            temp = Convert.ToUInt16(hanChar);

            // 캐릭터가 한글이 아닐 경우 처리
            if ((temp < m_UniCodeHangulBase) || temp > m_UniCodeHangulLast)
            {
                hi.isHangul = "NH";
                hi.oriChar = hanChar;
                hi.chars = null;
            }
            else
            {
                // nUniCode에 한글코드에 대한 유니코드 위치를 담고 이를 이용해 인덱스 계산
                int nUniCode = temp - m_UniCodeHangulBase;

                ChoSung = nUniCode / (21 * 28);
                nUniCode = nUniCode % (21 * 28);

                JungSung = nUniCode / 28;
                nUniCode = nUniCode % 28;

                JongSung = nUniCode;

                hi.isHangul = "H";
                hi.oriChar = hanChar;
                hi.chars = new char[] { HTable_ChoSung[ChoSung], HTable_JungSung[JungSung], HTable_JongSung[JongSung] };
            }
            return hi;
        }
    }

    public class IP
    {
        
        public string GetIP()
        {
            // 최신 사이트 접속을 위한 TLS 1.2 활성화 (강제 지정)
            // Windows 7 / .NET 4.0에서는 이 설정이 없으면 HTTPS 접속이 실패할 수 있습니다.
            try { ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; } catch { }

            string[] urls = {
                "http://checkip.amazonaws.com",
                "http://ipinfo.io/ip",
                "https://api.ipify.org"
            };

            foreach (var url in urls)
            {
                try
                {
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                    request.Timeout = 2000;
                    // 브라우저처럼 보이게 하기 위해 User-Agent 추가 (많은 사이트가 이를 요구함)
                    request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36";

                    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                    using (Stream stream = response.GetResponseStream())
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        string ip = reader.ReadToEnd().Trim();
                        // IP 형식인지 검증
                        IPAddress address;
                        if (IPAddress.TryParse(ip, out address))
                        {
                            // IPv4인 경우에만 반환 (필요시 IPv6 허용 가능)
                            if (address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                                return ip;
                        }
                    }
                }
                catch { continue; } // 다음 URL 시도
            }
            return "IP 확인 실패";
        }


        public string VersionInfo()
        {
            string version = "0";
            var fn = Application.StartupPath + "\\update.inf";
            if (System.IO.File.Exists(fn))
            {
                StreamReader sr = new StreamReader(fn);
                while (!sr.EndOfStream)
                {
                    string line = sr.ReadLine();
                    if (line.IndexOf("count=", 0) != -1)
                    {
                        version = line.Replace("count=", "");
                        break;
                    }
                }
            }

            return version;
        }
    }
}
