using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;

namespace ISBN_Check_test
{
    /// <summary>
    /// 알라딘 API 응답 데이터 구조체
    /// </summary>
    public class AladinBookData
    {
        public string Title { get; set; }
        public string Link { get; set; }
        public string Author { get; set; }
        public string PubDate { get; set; }
        public string Description { get; set; }
        public string Isbn { get; set; }
        public string Isbn13 { get; set; }
        public string PriceSales { get; set; }
        public string PriceStandard { get; set; }
        public string StockStatus { get; set; }
        public string Mileage { get; set; }
        public string Cover { get; set; }
        public string CategoryId { get; set; }
        public string CategoryName { get; set; }
        public string Publisher { get; set; }
        public string CustomerReviewRank { get; set; }
        public string FullDescription { get; set; }
        public string FullDescription2 { get; set; }
        public string ItemId { get; set; }

        /// <summary>
        /// 지정된 필드들을 "|" 구분자로 출력
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return $"{Title}|{Author}|{Publisher}|{Isbn13}|{PriceStandard}|{PubDate}|{CategoryName}|{StockStatus}";
        }
    }

    class API
    {
        /// <summary>
        /// https://blog.aladin.co.kr/openapi 참고
        /// </summary>
        /// <param name="Query"></param>
        /// <param name="QueryType"></param>
        /// <param name="Param"></param>
        /// <returns></returns>
        public string[] Aladin(string Query, string QueryType, string[] Param)
        {
            string result = string.Empty;
            // 쿼리 생성
            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();
            doc.LoadXml(xml);

            var xdoc = XDocument.Parse(xml);
            var xroot = xdoc.Root;

            // XML에서 직접 totalResults와 item 추출 (XDocument 사용)
            XNamespace ns = "http://www.aladin.co.kr/ttb/apiguide.aspx";

            // totalResults 추출
            string totalResults = xdoc.Descendants(ns + "totalResults").FirstOrDefault()?.Value ?? "0";

            // item들 추출
            var itemElements = xdoc.Descendants(ns + "item");

            if (!itemElements.Any())
            {
                return new string[] { };
            }

            int length = itemElements.Count();
            int ID_length = Param.Length;

            // XML item들을 순회하면서 필요한 데이터 추출 (XDocument 사용)
            List<string[]> retval = new List<string[]>();
            foreach (var itemElement in itemElements)
            {
                string[] buffer = new string[ID_length];
                for (int b = 0; b < ID_length; b++)
                {
                    buffer[b] = itemElement.Element(ns + Param[b])?.Value ?? "";
                }
                //retval.Add(buffer);
                return buffer;
            }
            return new string[] { };
        }

        /// <summary>
        /// https://blog.aladin.co.kr/openapi 참고 (구조체 반환 버전)
        /// </summary>
        /// <param name="Query"></param>
        /// <param name="QueryType"></param>
        /// <returns>AladinBookData 리스트</returns>
        public List<AladinBookData> Aladin_struct(string Query, string QueryType,out string xml)
        {
            // 쿼리 생성
            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());
            xml = string.Empty;
            try
            {
                // 쿼리를 입력인자로 WebRequest 개채 생성
                WebRequest request = WebRequest.Create(query);

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

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

                var xdoc = XDocument.Parse(xml);

                // XML에서 직접 totalResults와 item 추출 (XDocument 사용)
                XNamespace ns = "http://www.aladin.co.kr/ttb/apiguide.aspx";

                // totalResults 추출
                string totalResults = xdoc.Descendants(ns + "totalResults").FirstOrDefault()?.Value ?? "0";

                // item들 추출
                var itemElements = xdoc.Descendants(ns + "item");

                List<AladinBookData> resultList = new List<AladinBookData>();

                if (!itemElements.Any())
                {
                    Console.WriteLine(Query);
                    return resultList;
                }

                // 모든 item을 순회하며 리스트에 추가
                foreach (var itemElement in itemElements)
                {
                    AladinBookData bookData = new AladinBookData
                    {
                        ItemId = itemElement.Attribute("itemId")?.Value ?? "",
                        Title = itemElement.Element(ns + "title")?.Value ?? "",
                        Link = itemElement.Element(ns + "link")?.Value ?? "",
                        Author = itemElement.Element(ns + "author")?.Value ?? "",
                        PubDate = itemElement.Element(ns + "pubDate")?.Value ?? "",
                        Description = itemElement.Element(ns + "description")?.Value ?? "",
                        Isbn = itemElement.Element(ns + "isbn")?.Value ?? "",
                        Isbn13 = itemElement.Element(ns + "isbn13")?.Value ?? "",
                        PriceSales = itemElement.Element(ns + "priceSales")?.Value ?? "",
                        PriceStandard = itemElement.Element(ns + "priceStandard")?.Value ?? "",
                        StockStatus = itemElement.Element(ns + "stockStatus")?.Value ?? "",
                        Mileage = itemElement.Element(ns + "mileage")?.Value ?? "",
                        Cover = itemElement.Element(ns + "cover")?.Value ?? "",
                        CategoryId = itemElement.Element(ns + "categoryId")?.Value ?? "",
                        CategoryName = itemElement.Element(ns + "categoryName")?.Value ?? "",
                        Publisher = itemElement.Element(ns + "publisher")?.Value ?? "",
                        CustomerReviewRank = itemElement.Element(ns + "customerReviewRank")?.Value ?? "",
                        FullDescription = itemElement.Element(ns + "fulldescription")?.Value ?? "",
                        FullDescription2 = itemElement.Element(ns + "fulldescription2")?.Value ?? ""
                    };

                    resultList.Add(bookData);
                }

                return resultList;
            }
            catch (Exception ex)
            {
                // 에러 발생 시 빈 리스트 반환
                return new List<AladinBookData>();
            }
        }

        /// <summary>
        /// https://blog.aladin.co.kr/openapi 참고
        /// </summary>
        /// <param name="Query">ISBN값</param>
        /// <param name="QueryType">"ISBN"고정</param>
        /// <param name="Param">가져올 데이터</param>
        /// <returns></returns>
        public string Aladin_lookup(string Query, string QueryType, string[] Param)
        {
            string result = string.Empty;
            // 쿼리 생성
            string key = "ttbgloriabook1512001";
            string site = "http://www.aladin.co.kr/ttb/api/ItemLookUp.aspx";
            string query = string.Format("{0}?TTBKey={1}&itemIdType={2}&ItemId={3}&OptResult=categoryIdList",
                site, key, QueryType, Query);

            // 쿼리를 입력인자로 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();
            doc.LoadXml(xml);
            var json = JsonConvert.SerializeXmlNode(doc);
            // return json;

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

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

            // "object"내에 있는것을 얻어오기 위해 다시 dynamic변수에 참조
            dynamic docs = "";
            try
            {
                docs = dob["object"]["item"];
            }
            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)
                    {
                        tmp_data.Add(docs[Param[b]]);
                    }
                    else
                    {
                        tmp_data.Add(docs[a][Param[b]]);
                    }
                    result += tmp_data[b] + "|";
                }
                result += "\n";
            }
            return result;
        }
        public string Naver(string[] Query, string[] QueryType, string[] Param)
        {
            string result = string.Empty;
            string json = string.Empty;
            // url 생성
            string url = "https://openapi.naver.com/v1/search/book_adv?";

            for (int a = 0; a < Query.Length; a++)
            {
                url += string.Format("{0}={1}&", QueryType[a], Query[a]);
            }
            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
            {
                MessageBox.Show(status, "Error");
                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 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}&", url, Query, Type);
            WebRequest request = WebRequest.Create(query);

            string header = "KakaoAK e3935565b731a2a6f32880c90d76403a";

            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;
        }
    }
    class Skill_Grid
    {

        /// <summary>
        /// 그리드 앞 머리말에 넘버를 표시
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Print_Grid_Num(Object sender, DataGridViewRowPostPaintEventArgs e)
        {
            // RowPostPaint 이벤트 핸들러
            // 행헤더 열영역에 행번호를 위해 장방형으로 처리

            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>
        /// 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)
        {
            int rowIndex = ((DataGridView)sender).CurrentCell.RowIndex;
            int columnIndex = ((DataGridView)sender).CurrentCell.ColumnIndex;
            ((DataGridView)sender).Rows[rowIndex].Cells[columnIndex].Value = "";
        }
        /// <summary>
        /// 엑셀에서 복사한 데이터를 DataGirdView에 붙여넣어주는 코드 (단, KeyDown에 넣어야함!!!!)
        /// 사전에 if ((e.Shift && e.KeyCode == Keys.Insert) || (e.Control && e.KeyCode == Keys.V))안에 들어가야함.
        /// </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' };
                char[] columnSplitter = { '\t' };

                //get the text from clipboard
                IDataObject dataInClipboard = Clipboard.GetDataObject();

                string stringInClipboard = (string)dataInClipboard.GetData(DataFormats.Text);
                //split it into lines
                string[] rowsInClipboard = stringInClipboard.Split(rowSplitter, StringSplitOptions.RemoveEmptyEntries);
                //get the row and column of selected cell in dataGridView1
                int r = ((DataGridView)sender).SelectedCells[0].RowIndex;
                int c = ((DataGridView)sender).SelectedCells[0].ColumnIndex;
                //add rows into dataGridView1 to fit clipboard lines
                if (((DataGridView)sender).Rows.Count < (r + rowsInClipboard.Length))
                {
                    ((DataGridView)sender).Rows.Add(r + rowsInClipboard.Length - ((DataGridView)sender).Rows.Count);
                }
                // loop through the lines, split them into cells and place the values in the corresponding cell.
                for (int iRow = 0; iRow < rowsInClipboard.Length; 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 (((DataGridView)sender).ColumnCount - 1 >= c + iCol)
                        {
                            ((DataGridView)sender).Rows[r + iRow].Cells[c + iCol].Value = valuesInRow[iCol];
                        }
                    }
                }
            }
        }
    }
}
