using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using TABS.MailCarrier.WebSDK.Calendar;
using Tabs = TABS.MailCarrier.WebSDK.Calendar;
using TABS.MailCarrier.WebSDK.User;

public partial class Calendar_View : System.Web.UI.Page
{
    protected Guid _calId;          // 일정표 ID
    protected Guid _appId;          // 약속 ID
    protected Guid _recurId;        // 되풀이 약속 ID
    protected bool _recur;          // 되풀이 약속인지 여부
    protected string _sdate = "";   // 선택일자

    protected override void InitializeCulture()
    {
        string defLang = WebUser.CurrentUser.UiLanguage;
        Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(defLang);
        Thread.CurrentThread.CurrentUICulture = new CultureInfo(defLang);
        base.InitializeCulture();
    }

    protected void Page_Init(object sender, EventArgs e)
    {
        WebUtil.SetMcCommonCss(Page.Header);
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        _calId = WebParam.GetGuidParamValue("cid");
        _appId = WebParam.GetGuidParamValue("appid");
        _recurId = WebParam.GetGuidParamValue("recurid");
        _recur = _recurId != Guid.Empty && WebParam.GetStrParamValue("appid") == "";
        _sdate = WebParam.GetStrParamValue("sdate");

        if (!IsPostBack)
        {
            Page.Title = AppSetting.GetTitleInfo(Request).Title;

            McCalendar calendar = new McCalendar(_calId);
            McCalendar.RsAccessFlag accessFlag = McCalendar.GetAccessFlag(WebUser.CurrentUser.DomainUserID, _calId);
            if ((accessFlag & McCalendar.RsAccessFlag.Read) == 0)
            {
                Response.Redirect("~/Error.aspx?code=8", true);
                return;
            }

            // 내 일정표만 미리 알림 확인을 처리할 수 있다.
            // 일반 약속만 미리 알림 확인을 처리할 수 있다(되풀이 안됨)
            string calName = "", organizerEmail = "";
            if (!calendar.IsMine(WebUser.CurrentUser.DomainUserID))
            {
                calName = calendar.Name;
            }
            LoadAppointment(calName, out organizerEmail);

            // 권한에 따른 UI 조정: Admin 권한이 있거나 쓰기와 본인 작성 일정일 경우만 편집/삭제 가능
            bool editable = false;            
            if ((accessFlag & McCalendar.RsAccessFlag.Admin) > 0 ||
                ((accessFlag & McCalendar.RsAccessFlag.Write) > 0 && (organizerEmail == WebUser.CurrentUser.MailAddress || organizerEmail == "")))
            {
                editable = true;
            }
            BootstrapUtil.EnableButton(editToolButton, editable);
            BootstrapUtil.EnableButton(deleteToolButton, editable);
        }
    }

    protected void DeleteButton_Click(object sender, EventArgs e)
    {
        // 쓰기 권한 검사
        McCalendar.RsAccessFlag accessFlag = McCalendar.GetAccessFlag(WebUser.CurrentUser.DomainUserID, _calId);
        if ((accessFlag & (McCalendar.RsAccessFlag.Write | McCalendar.RsAccessFlag.Admin)) == 0)
        {
            Response.Redirect("~/Error.aspx?code=0", true);
            return;
        }

        if (!_recur)
        {
            if (_appId == Guid.Empty && WebParam.GetStrParamValue("appid") != "")
            {
                // 되풀이 예외 항목 중 하나 삭제
                //  - 존재하지 않는 항목이므로 예외 항목을 하나 생성한 후 RecurExceptionRemove 플래그를 셋 시킨다.
                DateTime exceptTime;
                if (DateTime.TryParse(WebParam.GetStrParamValue("begin"), out exceptTime))
                {
                    RecurrentAppointment appointment = new RecurrentAppointment(_recurId);
                    appointment.AddDeleteException(exceptTime);
                    WebOperationLog.Write(WebUser.CurrentUser.MailAddress, Request.UserHostAddress, "M/Calendar/View.aspx", "AddDeleteException", string.Format("CID:{0}, AID:{1}", _calId.ToString(), appointment.ID.ToString()));

                    if (appointment.IsOriginMeetingRequest)
                    {
                        appointment.Memo = MemoLabel.Text;
                        appointment.MeetingStatus = Tabs.Appointment.MeetingStatusType.MeetingIsCanceled;

                        MeetingRequest meetReq = new MeetingRequest(WebUser.CurrentUser.DomainUserID, WebUser.CurrentUser.Name, WebUser.CurrentUser.MailAddress);
                        meetReq.SendCancelMail(appointment);
                    }
                }
            }
            else
            {
                // 일반 및 되풀이 예외 항목 삭제
                Tabs.Appointment appointment = new Tabs.Appointment(_appId);
                appointment.Remove();       // 되풀이 예외의 경우 삭제 대신 RecurExceptionRemove 플래그가 셋된다.
                WebOperationLog.Write(WebUser.CurrentUser.MailAddress, Request.UserHostAddress, "M/Calendar/View.aspx", "Remove", string.Format("CID:{0}, AID:{1}", _calId.ToString(), appointment.ID.ToString()));

                if (appointment.IsOriginMeetingRequest)
                {
                    appointment.Memo = MemoLabel.Text;
                    appointment.MeetingStatus = Tabs.Appointment.MeetingStatusType.MeetingIsCanceled;

                    MeetingRequest meetReq = new MeetingRequest(WebUser.CurrentUser.DomainUserID, WebUser.CurrentUser.Name, WebUser.CurrentUser.MailAddress);
                    meetReq.SendCancelMail(appointment);
                }
            }
            if (_recurId != Guid.Empty)
            {
                // 되풀이 예외 삭제의 경우 명시적인 change 이벤트 발생 필요
                McCalendar calendar = new McCalendar(_calId);
                calendar.FireRecurrenceChangeEvent(_recurId);
            }
        }
        else
        {
            RecurrentAppointment appointment = new RecurrentAppointment(_recurId);
            appointment.Remove();
            WebOperationLog.Write(WebUser.CurrentUser.MailAddress, Request.UserHostAddress, "M/Calendar/View.aspx", "RemoveRecur", string.Format("CID:{0}, AID:{1}", _calId.ToString(), appointment.ID.ToString()));

            if (appointment.IsOriginMeetingRequest)
            {
                appointment.Memo = MemoLabel.Text;
                appointment.MeetingStatus = Tabs.Appointment.MeetingStatusType.MeetingIsCanceled;

                MeetingRequest meetReq = new MeetingRequest(WebUser.CurrentUser.DomainUserID, WebUser.CurrentUser.Name, WebUser.CurrentUser.MailAddress);
                meetReq.SendCancelMail(appointment);
            }
        }
        Response.Redirect(string.Format("Monthly.aspx?cid={0}&sdate={1}", _calId, _sdate), true);
    }

    private void LoadAppointment(string calName, out string organizerEmail)
    {
        if (!_recur)
        {
            if (_appId != Guid.Empty)
            {
                // 일반 약속
                Tabs.Appointment appointment = new Tabs.Appointment(_appId);
                appointment.Load();
                SubjectLabel.Text = GetSubject(calName, appointment.Subject);
                PlaceLabel.Text = appointment.Place;
                WriterLabel.Text = appointment.OrganizerName;
                if (appointment.Attendees.Count > 0)
                {
                    AttendeeListView.DataSource = appointment.Attendees;
                    AttendeeListView.DataBind();
                    BootstrapUtil.CollapseControl(AttendeePanel, false);        // AttendeePanel 출력
                }
                DateTime beginTime = appointment.BeginTime;
                DateTime endTime = appointment.EndTime;
                if ((appointment.Type & Tabs.Appointment.AppointmentType.AllDay) > 0)
                {
                    BeginDateLabel.Text = Resources.Calendar.AllDay2;
                    EndDateLabel.Text = "-";
                }
                else
                {
                    BeginDateLabel.Text = appointment.BeginTime.ToString("g");
                    EndDateLabel.Text = appointment.EndTime.ToString("g");
                }
                if ((appointment.Type & Tabs.Appointment.AppointmentType.Alert) > 0)
                    AlertLabel.Text = GetAlertString(appointment.AlertMinute);
                BusyStatusLabel.Text = GetBusyStatusString(appointment.BusyStatus);
                MemoLabel.Text = appointment.Memo;
                LoadInsertUpdateTime(appointment.InsertTime, appointment.UpdateTime);
                organizerEmail = appointment.OrganizerEmail;
            }
            else
            {
                // 되풀이 예외 약속 
                RecurrentAppointment appointment = new RecurrentAppointment(_recurId);
                appointment.Load();
                SubjectLabel.Text = GetSubject(calName, appointment.Subject);
                PlaceLabel.Text = appointment.Place;
                WriterLabel.Text = appointment.OrganizerName;
                if (appointment.Attendees.Count > 0)
                {
                    AttendeeListView.DataSource = appointment.Attendees;
                    AttendeeListView.DataBind();
                    BootstrapUtil.CollapseControl(AttendeePanel, false);        // AttendeePanel 출력
                }
                DateTime exceptTime, exBegin, exEnd;
                if (DateTime.TryParse(WebParam.GetStrParamValue("begin"), out exceptTime))
                {
                    TimeSpan ts = exceptTime - appointment.BeginTime;
                    exBegin = appointment.BeginTime.AddMinutes(ts.TotalMinutes);
                    exEnd = appointment.EndTime.AddMinutes(ts.TotalMinutes);
                }
                else
                {
                    exBegin = WebUser.CurrentUser.ToLocalTime(appointment.BeginTime);
                    exEnd = WebUser.CurrentUser.ToLocalTime(appointment.EndTime);
                }
                if ((appointment.Type & Tabs.Appointment.AppointmentType.AllDay) > 0)
                {
                    BeginDateLabel.Text = Resources.Calendar.AllDay2;
                    EndDateLabel.Text = "-";
                }
                else
                {
                    BeginDateLabel.Text = exBegin.ToString("g");
                    EndDateLabel.Text = exEnd.ToString("g");
                }
                if ((appointment.Type & Tabs.Appointment.AppointmentType.Alert) > 0)
                    AlertLabel.Text = GetAlertString(appointment.AlertMinute);
                BusyStatusLabel.Text = GetBusyStatusString(appointment.BusyStatus);
                MemoLabel.Text = appointment.Memo;
                LoadInsertUpdateTime(appointment.InsertTime, appointment.UpdateTime);
                organizerEmail = appointment.OrganizerEmail;
            }
        }
        else
        {
            // 되풀이 약속
            LoadRecurAppointment(calName, out organizerEmail);
        }
    }

    private void LoadRecurAppointment(string calName, out string organizerEmail)
    {
        RecurrentAppointment appointment = new RecurrentAppointment(_recurId);
        appointment.Load();
        SubjectLabel.Text = GetSubject(calName, appointment.Subject);
        PlaceLabel.Text = appointment.Place;
        WriterLabel.Text = appointment.OrganizerName;
        if (appointment.Attendees.Count > 0)
        {
            AttendeeListView.DataSource = appointment.Attendees;
            AttendeeListView.DataBind();
            BootstrapUtil.CollapseControl(AttendeePanel, false);        // AttendeePanel 출력
        }
        DateTime beginTime = appointment.BeginTime;
        DateTime endTime = appointment.EndTime;
        if ((appointment.Type & Tabs.Appointment.AppointmentType.AllDay) > 0)
        {
            BeginDateLabel.Text = Resources.Calendar.AllDay2;
            EndDateLabel.Text = "-";
        }
        else
        {
            BeginDateLabel.Text = appointment.BeginTime.ToString("g");
            EndDateLabel.Text = appointment.EndTime.ToString("g");
        }
        RecurLabel.Text = GetRecurString(appointment);
        if ((appointment.Type & Tabs.Appointment.AppointmentType.Alert) > 0)
            AlertLabel.Text = GetAlertString(appointment.AlertMinute);
        BusyStatusLabel.Text = GetBusyStatusString(appointment.BusyStatus);
        MemoLabel.Text = appointment.Memo;
        LoadInsertUpdateTime(appointment.InsertTime, appointment.UpdateTime); organizerEmail = appointment.OrganizerEmail;
    }

    #region Calendar view support methods

    private string GetSubject(string calName, string subject)
    {
        return (calName != "") ? string.Format("[{0}] {1}", calName, subject) : subject;
    }

    private string GetAlertString(int alertMin)
    {
        string alertStr = "";
        if (alertMin < 60)
        {
            alertStr = string.Format(Resources.Calendar.Alert1, alertMin);
        }
        else if (alertMin < 1440)
        {
            int restMin = alertMin % 60;
            if (restMin == 0)
                alertStr = string.Format(Resources.Calendar.Alert2, alertMin / 60);
            else
                alertStr = string.Format(Resources.Calendar.Alert3, alertMin / 60, restMin);
        }
        else
        {
            int restHour = (alertMin % (60 * 24)) % 60;
            int restMin = alertMin % 60;
            if (restHour == 0)
            {
                if (restMin == 0)
                    alertStr = string.Format(Resources.Calendar.Alert4, alertMin / (60 * 24));
                else
                    alertStr = string.Format(Resources.Calendar.Alert5, alertMin / (60 * 24), restMin);
            }
            else
            {
                if (restMin == 0)
                    alertStr = string.Format(Resources.Calendar.Alert6, alertMin / (60 * 24), alertMin / 60);
                else
                    alertStr = string.Format(Resources.Calendar.Alert7, alertMin / (60 * 24), alertMin / 60, restMin);
            }
        }
        return string.Format(Resources.Calendar.Alert8, alertStr);
    }

    private string GetRecurString(RecurrentAppointment appointment)
    {
        string retval = "";
        switch (appointment.RecurType)
        {
            case RecurrentAppointment.RecurrentType.EveryDay:
                retval = string.Format(Resources.Calendar.Recur1, appointment.Recurrence.Interval);
                break;
            case RecurrentAppointment.RecurrentType.EveryWeek:
                retval = string.Format(Resources.Calendar.Recur2, appointment.Recurrence.Interval,
                    GetDayOfWeekString(appointment.Recurrence.DayOfWeek));
                break;
            case RecurrentAppointment.RecurrentType.EveryMonth:
                retval = string.Format(Resources.Calendar.Recur3, appointment.Recurrence.Interval);
                break;
            case RecurrentAppointment.RecurrentType.EveryMonthDay:
                retval = string.Format(Resources.Calendar.Recur4, appointment.Recurrence.Interval,
                    GetWeekOfMonthString(appointment.Recurrence.WeekOfMonth), GetDayOfWeekString(appointment.Recurrence.DayOfWeek));
                break;
            case RecurrentAppointment.RecurrentType.EveryYear:
                retval = string.Format(Resources.Calendar.Recur5, appointment.Recurrence.Interval);
                break;
            case RecurrentAppointment.RecurrentType.EveryYearDay:
                retval = string.Format(Resources.Calendar.Recur6, appointment.Recurrence.Interval,
                    appointment.Recurrence.MonthOfYear,
                    GetWeekOfMonthString(appointment.Recurrence.WeekOfMonth), GetDayOfWeekString(appointment.Recurrence.DayOfWeek));
                break;
        }
        return retval;
    }

    private string GetBusyStatusString(Tabs.Appointment.BusyStatusType busyStatus)
    {
        string retval = "";
        switch (busyStatus)
        {
            case Tabs.Appointment.BusyStatusType.Free: retval = Resources.Calendar.BusyStatus1; break;
            case Tabs.Appointment.BusyStatusType.Tentative: retval = Resources.Calendar.BusyStatus2; break;
            case Tabs.Appointment.BusyStatusType.Busy: retval = Resources.Calendar.BusyStatus3; break;
            case Tabs.Appointment.BusyStatusType.OutOfOffice: retval = Resources.Calendar.BusyStatus4; break;
        }
        return retval;
    }

    private string GetDayOfWeekString(int dayOfWeek)
    {
        string retval = "";
        if ((dayOfWeek & 1) > 0) retval += Resources.Calendar.WeekDay1;
        if ((dayOfWeek & 2) > 0) retval += Resources.Calendar.WeekDay2;
        if ((dayOfWeek & 4) > 0) retval += Resources.Calendar.WeekDay3;
        if ((dayOfWeek & 8) > 0) retval += Resources.Calendar.WeekDay4;
        if ((dayOfWeek & 16) > 0) retval += Resources.Calendar.WeekDay5;
        if ((dayOfWeek & 32) > 0) retval += Resources.Calendar.WeekDay6;
        if ((dayOfWeek & 64) > 0) retval += Resources.Calendar.WeekDay7;
        return retval;
    }

    private string GetWeekOfMonthString(int weekOfMonth)
    {
        string retval = "";
        switch (weekOfMonth)
        {
            case 1: retval = Resources.Calendar.WeekOfMonth1; break;
            case 2: retval = Resources.Calendar.WeekOfMonth2; break;
            case 3: retval = Resources.Calendar.WeekOfMonth3; break;
            case 4: retval = Resources.Calendar.WeekOfMonth4; break;
            case 5: retval = Resources.Calendar.WeekOfMonth5; break;
        }
        return retval;
    }

    protected string GetAttendeeStatusString(Attendee.AttendeeStatus status)
    {
        string retval = "";
        switch (status)
        {
            case Attendee.AttendeeStatus.ResponseUnknown: retval = Resources.Calendar.AttendeeStatus1; break;
            case Attendee.AttendeeStatus.Tentative: retval = Resources.Calendar.AttendeeStatus2; break;
            case Attendee.AttendeeStatus.Accept: retval = Resources.Calendar.AttendeeStatus3; break;
            case Attendee.AttendeeStatus.Decline: retval = Resources.Calendar.AttendeeStatus4; break;
        }
        return retval;
    }

    private void LoadInsertUpdateTime(DateTime? insertTime, DateTime? updateTime)
    {
        if (AppSetting.ShowAppCreationTime && insertTime.HasValue)
        {
            if (insertTime == updateTime)
                WriteDateLabel.Text = string.Format(GetLocalResourceObject("InsertTime1").ToString(), insertTime);
            else
                WriteDateLabel.Text = string.Format(GetLocalResourceObject("InsertTime2").ToString(), insertTime, updateTime);
        }
    }

    #endregion
}