using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;

namespace BaroSeeSDK.Example.Controllers
{
    public class HomeController : Controller
    {
        private static string TokenCacheFile = "";

        private DocumentInfo[] documents = new DocumentInfo[]
        {
            new DocumentInfo(){ Ext ="hwp", Name = "파일한글컨트롤프로그래밍.hwp", Url = "http://www.must.or.kr/ko/support/update/?f=4068|%ed%95%9c%ea%b8%80%ec%bb%a8%ed%8a%b8%eb%a1%a4%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%98%eb%b0%8d.hwp"},
            new DocumentInfo(){ Ext = "xls", Name = "sample.xls", Url = "http://www.must.or.kr/ko/support/update/?f=4069|sample.xls"},
            new DocumentInfo(){ Ext = "xlsx", Name = "Welcome+to+Excel.xlsx", Url = "http://www.must.or.kr/ko/support/update/?f=4070|Welcome+to+Excel.xlsx"},
            new DocumentInfo(){ Ext = "doc", Name = "sample.doc", Url = "http://www.must.or.kr/ko/support/update/?f=4073|sample.doc"},
            new DocumentInfo(){ Ext = "docx", Name = "Welcome+to+Word.docx", Url = "http://www.must.or.kr/ko/support/update/?f=4074|Welcome+to+Word.docx"},
        };

        private BaroSeeWorker worker;

        private string publicKey = "API 키"; //API 키
        private string privateKey = "API 시크릿"; //API 시크릿        

        protected void UseBaroSeeSDKWithSession(HttpContext context)
        {
            string token = "" + context.Session["BaroSeeSDK.Token"];
            DateTime? expiredAt = DateTime.UtcNow;
            if (string.IsNullOrEmpty(token))
            {
                context.Session["BaroSeeSDK.Token"] = "";
                context.Session["BaroSeeSDK.TokenExpiredAt"] = null;
            }
            else
            {
                //Try to use previous token if possible
                token = "" + context.Session["BaroSeeSDK.Token"];
                expiredAt = (DateTime?)context.Session["BaroSeeSDK.TokenExpiredAt"];
                if (expiredAt.HasValue && expiredAt.Value <= DateTime.UtcNow)
                {
                    context.Session["BaroSeeSDK.Token"] = "";
                    context.Session["BaroSeeSDK.TokenExpiredAt"] = null;
                    token = null;
                    expiredAt = null;
                }
            }

            worker = new BaroSeeWorker() { };
            worker.OnAccessTokenChanged += new AuthenticationProvider.AccessTokenChangedEvent(delegate(AccessToken newToken) {
                //Remember current token                            
                if (newToken != null)
                {
                    context.Session["BaroSeeSDK.Token"] = newToken.Value;
                    context.Session["BaroSeeSDK.TokenExpiredAt"] = newToken.ExpiredAt;
                }
            });
            worker.Configure(publicKey, privateKey, token);
        }

        protected void UseBaroSeeSDKWithFile(String filePath)
        {
            TokenCacheFile = filePath;

            FileInfo info = new FileInfo(filePath);
            string token = "";

            DateTime? expiredAt = DateTime.UtcNow;
            if (!info.Exists)
            {
                token = "";
                expiredAt = null;
            }
            else
            {
                //Try to use previous token if possible                
                AccessToken origin = null;
                JavaScriptSerializer js = new JavaScriptSerializer();                
                try {                        
                    string json = System.IO.File.ReadAllText(filePath);
                    origin = js.Deserialize<AccessToken>(json);                    
                } catch { Thread.Sleep(500); }
                if (origin != null && origin.ExpiredAt > DateTime.UtcNow)
                {
                    token = origin.Value;
                    expiredAt = origin.ExpiredAt;
                }
            }

            worker = new BaroSeeWorker() { };
            worker.OnAccessTokenChanged += new AuthenticationProvider.AccessTokenChangedEvent(delegate (AccessToken newToken) {
                //Remember current token                            
                if (newToken != null)
                {
                    JavaScriptSerializer js = new JavaScriptSerializer();                    
                    try
                    {
                        string json = js.Serialize(newToken);
                        System.IO.File.WriteAllText(filePath, json);
                        token = newToken.Value;
                        expiredAt = newToken.ExpiredAt;                            
                    }
                    catch {  };                    
                }
            });
            worker.Configure(publicKey, privateKey, token);
        }


        public ActionResult Index()
        {
            return View(documents);
        }

        public ActionResult Subscribe(string url)
        {
            DocumentInfo value = null;
            url = Uri.UnescapeDataString(url);
            value = worker.SDK.DocumentAPI.Subscribe(url, true, ErrorHandler);
            return Json(value != null, JsonRequestBehavior.AllowGet);
        }

        public ActionResult Info(string url)
        {
            DocumentInfo value = null;
            url = Uri.UnescapeDataString(url);
            value = worker.SDK.DocumentAPI.Info(url, ErrorHandler);
            return Json(value, JsonRequestBehavior.AllowGet);
        }

        public ActionResult Delete(string url)
        {
            bool value = false;
            url = Uri.UnescapeDataString(url);
            value = worker.SDK.DocumentAPI.Delete(url, ErrorHandler);
            return Json(value, JsonRequestBehavior.AllowGet);
        }

        public ActionResult NotifyChange(string url)
        {
            bool value = false;
            url = Uri.UnescapeDataString(url);
            value = worker.SDK.DocumentAPI.SetChange(url, ErrorHandler);
            return Json(value, JsonRequestBehavior.AllowGet);
        }

        public ActionResult GetHtml(string url)
        {
            url = Uri.UnescapeDataString(url);
            using (Task<Stream> result = worker.SDK.DocumentAPI.GetHTML(url, ErrorHandler))
            {
                if (result == null || result.Result == null || !result.Result.CanRead)
                    return Error("Cannot read the file's content as html string");
                using (StreamReader s = new StreamReader(result.Result))
                {
                    return Content(s.ReadToEnd());
                }
            }
        }

        public ActionResult ViewFile(string url)
        {
            url = Uri.UnescapeDataString(url);
            DocumentInfo info = worker.SDK.DocumentAPI.Info(url, ErrorHandler);            

            ViewBag.Url = url;
            ViewBag.DocumentInfo = info;
            return View();
        }

        public async Task<ActionResult> Download(string url)
        {
            url = Uri.UnescapeDataString(url);
            HttpResponseMessage response = worker.SDK.DocumentAPI.DownloadConvertedFile(url, ErrorHandler);            
            try
            {
                if (response != null && response.IsSuccessStatusCode)
                {
                    string strDisposition = response.Content.Headers.GetValues("Content-Disposition").FirstOrDefault();
                    ContentDispositionHeaderValue disposition = ContentDispositionHeaderValue.Parse(strDisposition);
                    String fileName = ""+disposition.FileName;
                    fileName = fileName.StartsWith("?f=") ? fileName.Substring(3) : fileName;
                    fileName = fileName.StartsWith("\"") ? fileName.Substring(1, fileName.Length - 2) : fileName;                    
                    string ext = Path.GetExtension(fileName).ToLower();                    
                    string contentType = DocumentInfo.GetContentType(ext);
                    if (string.IsNullOrEmpty(contentType)) throw new Exception("Invalid file extension");
                    return File(response.Content.ReadAsStreamAsync().Result, contentType, fileName);
                }
                throw new Exception("Cannot download file from provider");
            }
            catch (Exception ex)
            {
                return Error(ex.Message);
            }            
        }

        public ActionResult GetFile(string url)
        {
            url = Uri.UnescapeDataString(url);
            DocumentInfo info = worker.SDK.DocumentAPI.Info(url, ErrorHandler);
            if (info != null)
            {
                HttpResponseMessage response = worker.SDK.DocumentAPI.DownloadConvertedFile(url, ErrorHandler);
                if (info.TargetFormat == "html")
                {
                    return Content(response.Content.ReadAsStringAsync().Result);
                }
                if (info.TargetFormat == "pdf")
                {
                    return File(response.Content.ReadAsStreamAsync().Result, "application/pdf");
                }
            }
            return Error("File is not found or wrong format");
        }

        public ActionResult Error(string message)
        {
            ViewBag.Message = message;

            return View("Error");
        }

        protected void ErrorHandler(string senderId, HttpStatusCode code, string message)
        {
            if (code == HttpStatusCode.Unauthorized)
            {
                if (!string.IsNullOrEmpty(TokenCacheFile))
                {
                    try { System.IO.File.Delete(TokenCacheFile); } catch { }
                }
                else
                {
                    Session["BaroSeeSDK.Token"] = null;
                    Session["BaroSeeSDK.TokenExpiredAt"] = null;
                }
            }
            //TODO: Log Error or Do a task;
            //Response.RedirectToRoute("Error_Route", new { message = string.Format("{0}: {1} - {2}", senderId, code.ToString(), message) });
        }

        protected override void OnActionExecuting(ActionExecutingContext context)
        {
            base.OnActionExecuting(context);
            //UseBaroSeeSDKWithSession(context.HttpContext.ApplicationInstance.Context);
            string filePath = Server.MapPath("~/App_Data/barose_token.cache");
            UseBaroSeeSDKWithFile(filePath);
        }
    }
}