using System;
using System.Data;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.ComponentModel;

using System.IO;
using System.Net;
using System.Collections.Generic;
using MyKarte.Service.Impl;
using MyKarte.Service.WebReference;

namespace MyKarte.Service
{
    /// <summary>
    /// RetrieveService クラス
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(false)]
    public class RetrieveService : System.Web.Services.WebService
    {
        /// <summary>
        /// 認証する。
        /// </summary>
        /// <param name="args">引数</param>
        /// <returns>true: OK, false: NG</returns>
        [WebMethod(EnableSession = true)]
        public bool Authenticate(string[] args)
        {
            IAttachment attachment = GetAttachment();

            bool auth = attachment.Authenticate(args);

            Session["Auth"] = auth;

            return auth;
        }

        /// <summary>
        /// コールバック情報を設定する。
        /// </summary>
        /// <param name="info">コールバック情報</param>
        [WebMethod(EnableSession = true)]
        public void SetCallbackInfo(string[] info)
        {
            CheckAuth();

            // エンドポイント
            Session["Endpoint"] = info[0];

            // 施設ID
            Session["FacilityId"] = info[1];

            // 暗号化ID
            Session["EncryptedId"] = info[2];

            // サービスID
            Session["ServiceId"] = info[3];
        }

        /// <summary>
        /// 患者IDを取得する。
        /// </summary>
        /// <returns>患者ID</returns>
        [WebMethod(EnableSession = true)]
        public string GetPatient()
        {
            CheckAuth();

            IAttachment attachment = GetAttachment();

            return attachment.GetPatient();
        }

        /// <summary>
        /// 患者IDを設定する。
        /// </summary>
        /// <param name="patientId">患者ID</param>
        [WebMethod(EnableSession = true)]
        public void SetPatient(string patientId)
        {
            CheckAuth();

            IAttachment attachment = GetAttachment();

            // 患者ID
            Session["PatientId"] = patientId;

            attachment.SetPatient(patientId);
        }

        /// <summary>
        /// type, attribute を設定する。
        /// </summary>
        /// <param name="props">type, attribute</param>
        [WebMethod(EnableSession = true)]
        public void SetProperties(string[] props)
        {
            CheckAuth();

            IAttachment attachment = GetAttachment();

            // タイプ
            Session["Type"] = props[0];

            // 属性
            Session["Attribute"] = props[1];

            attachment.SetProperties(props);
        }

        /// <summary>
        /// 日付を取得する。
        /// </summary>
        /// <param name="startDate">開始日</param>
        /// <param name="endDate">終了日</param>
        /// <param name="diff">差分</param>
        /// <returns>日付</returns>
        [WebMethod(EnableSession = true)]
        public string[] GetDates(string startDate, string endDate, bool diff)
        {
            CheckAuth();

            IAttachment attachment = GetAttachment();

            DateTime sd = DateTime.ParseExact(startDate, "yyyy-MM-dd", null);
            DateTime ed = DateTime.ParseExact(endDate, "yyyy-MM-dd", null);

            DateTime[] dates = attachment.GetDates(sd, ed, diff);

            string[] results = Array.ConvertAll<DateTime, string>(dates,
                delegate(DateTime param)
                {
                    return param.ToString("yyyy-MM-dd");
                });

            return results;
        }

        /// <summary>
        /// 指定した日付のデータを文字列として取得する。
        /// </summary>
        /// <param name="date">日付</param>
        /// <returns>文字列</returns>
        [WebMethod(EnableSession = true)]
        public string GetContent(string date)
        {
            CheckAuth();

            IAttachment attachment = GetAttachment();

            DateTime d = DateTime.ParseExact(date, "yyyy-MM-dd", null);

            return attachment.GetContent(d);
        }

        /// <summary>
        /// 指定した日付のデータをファイルとして取得する。
        /// </summary>
        /// <param name="date">日付</param>
        /// <returns>結果</returns>
        [WebMethod(EnableSession = true)]
        public string GetFiles(string date)
        {
            CheckAuth();

            IAttachment attachment = GetAttachment();

            //------------------------//
            //   Attachmentサービス   //
            //------------------------//
            bool @return;
            bool returnSpecified;

            bool dateSpecified = true;
            bool uniqueIdSpecified = true;

            AttachmentService attachmentService = new AttachmentService();

            attachmentService.CookieContainer = new CookieContainer();

            // MTOM形式
            attachmentService.RequireMtom = true;

            // エンドポイント
            string endpoint = (string)Session["Endpoint"];
            attachmentService.Url = endpoint;

            // 施設ID
            string facilityId = (string)Session["FacilityId"];

            // 暗号化ID
            string encryptedId = (string)Session["EncryptedId"];

            attachmentService.authenticate(new string[] { facilityId, encryptedId }, out @return, out returnSpecified);

            if (returnSpecified && !@return)
            {
                throw new SoapException("AttachmentServiceの認証に失敗しました。", SoapException.ClientFaultCode);
            }

            // サービスID
            string serviceId = (string)Session["ServiceId"];
            attachmentService.setServiceId(serviceId, out @return, out returnSpecified);

            // 患者ID
            string patientId = (string)Session["PatientId"];
            attachmentService.setPatientId(patientId, out @return, out returnSpecified);

            // タイプ
            string type = (string)Session["Type"];
            attachmentService.setType(type, out @return, out returnSpecified);

            // 属性
            string attribute = (string)Session["Attribute"];
            attachmentService.setAttribute(attribute, out @return, out returnSpecified);

            // 日付
            DateTime d = DateTime.ParseExact(date, "yyyy-MM-dd", null);
            attachmentService.setDate(d, dateSpecified, out @return, out returnSpecified);

            Dictionary<string, string> files = attachment.GetFiles(d);
            bool[] results = new bool[files.Count];

            int i = 0;
            foreach (KeyValuePair<string, string> kvp in files)
            {
                // 拡張子
                string extension = Path.GetExtension(kvp.Key).ToLower().TrimStart('.');

                if (string.IsNullOrEmpty(extension))
                {
                    throw new SoapException("ファイルの拡張子がありません。", SoapException.ServerFaultCode);
                }

                attachmentService.setExtension(extension, out @return, out returnSpecified);

                // descriptionId
                string descriptionId = kvp.Value;

                if (string.IsNullOrEmpty(descriptionId))
                {
                    attachmentService.setDescriptionId("", out @return, out returnSpecified);
                }
                else
                {
                    attachmentService.setDescriptionId(descriptionId, out @return, out returnSpecified);
                }

                try
                {
                    // ファイルデータ
                    byte[] fileData = null;

                    using (FileStream fs = new FileStream(kvp.Key, FileMode.Open, FileAccess.Read))
                    {
                        fileData = new byte[fs.Length];
                        fs.Read(fileData, 0, fileData.Length);
                    }

                    attachmentService.store(i, uniqueIdSpecified, fileData, out @return, out returnSpecified);

                    if (returnSpecified)
                    {
                        results[i] = @return;
                    }
                }
                catch (Exception)
                {
                }

                i++;
            }

            bool result = Array.TrueForAll<bool>(results,
                delegate(bool param)
                {
                    return param == true;
                });

            if (result)
            {
                // 全件成功
                return "Success";
            }

            result = Array.TrueForAll<bool>(results,
                delegate(bool param)
                {
                    return param == false;
                });

            if (result)
            {
                // 全件失敗
                return "Failure";
            }

            // 一部失敗
            return "Warning";
        }

        /// <summary>
        /// IAttachment を取得する。
        /// </summary>
        /// <returns>IAttachment</returns>
        private IAttachment GetAttachment()
        {
            IAttachment attachment;

            attachment = (IAttachment)Session["Attachment"];

            if (attachment == null)
            {
                attachment = AttachmentFactory.Create();

                Session["Attachment"] = attachment;
            }

            return attachment;
        }

        /// <summary>
        /// 認証されているか確認する。
        /// </summary>
        private void CheckAuth()
        {
            bool auth = (bool)(Session["Auth"] ?? false);

            if (!auth)
            {
                throw new SoapException("認証されていません。", SoapException.ClientFaultCode);
            }
        }
    }
}
