/*
 * 版权所有 (c) 2010-2011，MiCode 开源社区 (www.micode.net)
 * 根据 Apache 许可证 2.0 版本（"许可证"）授权；
 * 除非符合许可证的规定，否则不得使用本文件。
 * 您可以从以下网址获取许可证副本：
 * http://www.apache.org/licenses/LICENSE-2.0
 * 除非适用法律要求或书面同意，本软件按"原样"分发，
 * 没有任何明示或暗示的保证或条件。
 * 详见许可证中规定的权限和限制。
 * （注：这是一份标准的Apache许可证2.0版本的开源声明）
 */
// 定义包路径
package net.micode.notes.ui;

// 导入Java工具类
import java.text.DateFormatSymbols;   // 用于获取AM/PM本地化字符串
import java.util.Calendar;          // 日期时间处理类

// 导入项目资源
import net.micode.notes.R;          // 资源ID引用

// 导入Android相关类
import android.content.Context;      // 上下文对象
import android.text.format.DateFormat;  // 日期格式化工具
import android.view.View;           // 基础视图类
import android.widget.FrameLayout;  // 帧布局容器
import android.widget.NumberPicker;//  数字选择器控件

/**
 * 自定义日期时间选择器组件
 * 包含日期、小时、分钟和AM/PM选择器
 */
public class DateTimePicker extends FrameLayout {
    // 默认启用状态
    private static final boolean DEFAULT_ENABLE_STATE = true;

    // 时间相关常量
    private static final int HOURS_IN_HALF_DAY = 12;    // 半天的12小时
    private static final int HOURS_IN_ALL_DAY = 24;     // 全天24小时
    private static final int DAYS_IN_ALL_WEEK = 7;     // 一周7天

    // 数字选择器范围常量
    private static final int DATE_SPINNER_MIN_VAL = 0;
    private static final int DATE_SPINNER_MAX_VAL = DAYS_IN_ALL_WEEK - 1;
    private static final int HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW = 0;
    private static final int HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW = 23;
    private static final int HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW = 1;
    private static final int HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW = 12;
    private static final int MINUT_SPINNER_MIN_VAL = 0;
    private static final int MINUT_SPINNER_MAX_VAL = 59;
    private static final int AMPM_SPINNER_MIN_VAL = 0;
    private static final int AMPM_SPINNER_MAX_VAL = 1;
    // 控件成员变量
    private final NumberPicker mDateSpinner;   // 日期选择器
    private final NumberPicker mHourSpinner;   // 小时选择器
    private final NumberPicker mMinuteSpinner;// 分钟选择器
    private final NumberPicker mAmPmSpinner; // AM/PM选择器
    // 状态变量
    private Calendar mDate;                    // 当前选择的日期时间
    private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK]; // 日期显示值数组
    private boolean mIsAm;                    // 是否为上午
    private boolean mIs24HourView;            // 是否为24小时制
    private boolean mIsEnabled = DEFAULT_ENABLE_STATE; // 是否启用
    private boolean mInitialising;             // 是否正在初始化

    // 回调接口
    private OnDateTimeChangedListener mOnDateTimeChangedListener;

    // 日期变化监听器
    private NumberPicker.OnValueChangeListener mOnDateChangedListener =
            new NumberPicker.OnValueChangeListener() {
                @Override
                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
                    // 计算日期差值并更新日历
                    mDate.add(Calendar.DAY_OF_YEAR,  newVal - oldVal);
                    updateDateControl();      // 更新日期显示
                    onDateTimeChanged();     // 触发回调
                }
            };

    // 小时变化监听器（处理12/24小时制的复杂逻辑）
    private NumberPicker.OnValueChangeListener mOnHourChangedListener =
            new NumberPicker.OnValueChangeListener() {
                @Override
                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
                    boolean isDateChanged = false;
                    Calendar cal = Calendar.getInstance();

                    // 处理12小时制下的日期变更
                    if (!mIs24HourView) {
                        // 从PM到AM跨日情况
                        if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) {
                            cal.setTimeInMillis(mDate.getTimeInMillis());
                            cal.add(Calendar.DAY_OF_YEAR,  1);
                            isDateChanged = true;
                        }
                        // 从AM到PM跨日情况
                        else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
                            cal.setTimeInMillis(mDate.getTimeInMillis());
                            cal.add(Calendar.DAY_OF_YEAR,  -1);
                            isDateChanged = true;
                        }
                        // AM/PM切换点检查
                        if (oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY ||
                                oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
                            mIsAm = !mIsAm;
                            updateAmPmControl();
                        }
                    }
                    // 处理24小时制下的日期变更
                    else {
                        // 23点转到0点（次日）
                        if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) {
                            cal.setTimeInMillis(mDate.getTimeInMillis());
                            cal.add(Calendar.DAY_OF_YEAR,  1);
                            isDateChanged = true;
                        }
                        // 0点转到23点（前一天）
                        else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {
                            cal.setTimeInMillis(mDate.getTimeInMillis());
                            cal.add(Calendar.DAY_OF_YEAR,  -1);
                            isDateChanged = true;
                        }
                    }

                    // 更新实际小时值（考虑AM/PM）
                    int newHour = mHourSpinner.getValue()  % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY);
                    mDate.set(Calendar.HOUR_OF_DAY,  newHour);
                    onDateTimeChanged();

                    // 处理需要变更日期的情况
                    if (isDateChanged) {
                        setCurrentYear(cal.get(Calendar.YEAR));
                        setCurrentMonth(cal.get(Calendar.MONTH));
                        setCurrentDay(cal.get(Calendar.DAY_OF_MONTH));
                    }
                }
            };

    // 分钟变化监听器（处理59->00和00->59的边界情况）
    private NumberPicker.OnValueChangeListener mOnMinuteChangedListener =
            new NumberPicker.OnValueChangeListener() {
                @Override
                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
                    int minValue = mMinuteSpinner.getMinValue();
                    int maxValue = mMinuteSpinner.getMaxValue();
                    int offset = 0;

                    // 处理分钟循环滚动情况
                    if (oldVal == maxValue && newVal == minValue) {
                        offset += 1; // 下一小时
                    } else if (oldVal == minValue && newVal == maxValue) {
                        offset -= 1; // 上一小时
                    }

                    if (offset != 0) {
                        mDate.add(Calendar.HOUR_OF_DAY,  offset);
                        mHourSpinner.setValue(getCurrentHour());
                        updateDateControl();

                        // 处理AM/PM切换
                        int newHour = getCurrentHourOfDay();
                        if (newHour >= HOURS_IN_HALF_DAY) {
                            mIsAm = false;
                            updateAmPmControl();
                        } else {
                            mIsAm = true;
                            updateAmPmControl();
                        }
                    }

                    mDate.set(Calendar.MINUTE,  newVal);
                    onDateTimeChanged();
                }
            };

    // AM/PM变化监听器
    private NumberPicker.OnValueChangeListener mOnAmPmChangedListener =
            new NumberPicker.OnValueChangeListener() {
                @Override
                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
                    mIsAm = !mIsAm; // 切换AM/PM状态

                    // 调整12小时
                    if (mIsAm) {
                        mDate.add(Calendar.HOUR_OF_DAY,  -HOURS_IN_HALF_DAY);
                    } else {
                        mDate.add(Calendar.HOUR_OF_DAY,  HOURS_IN_HALF_DAY);
                    }

                    updateAmPmControl();
                    onDateTimeChanged();
                }
            };

    /**
     * 日期时间变化回调接口
     */
    public interface OnDateTimeChangedListener {
        void onDateTimeChanged(DateTimePicker view, int year, int month,
                               int dayOfMonth, int hourOfDay, int minute);
    }

    // 构造函数（使用当前时间）
    public DateTimePicker(Context context) {
        this(context, System.currentTimeMillis());
    }

    // 构造函数（指定时间戳）
    public DateTimePicker(Context context, long date) {
        this(context, date, DateFormat.is24HourFormat(context));
    }

    // 主构造函数
    public DateTimePicker(Context context, long date, boolean is24HourView) {
        super(context);
        mDate = Calendar.getInstance();
        mInitialising = true;
        mIsAm = (getCurrentHourOfDay() < HOURS_IN_HALF_DAY);

        // 加载布局
        inflate(context, R.layout.datetime_picker,  this);

        // 初始化日期选择器
        mDateSpinner = (NumberPicker) findViewById(R.id.date);
        mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL);
        mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL);
        mDateSpinner.setOnValueChangedListener(mOnDateChangedListener);

        // 初始化小时选择器
        mHourSpinner = (NumberPicker) findViewById(R.id.hour);
        mHourSpinner.setOnValueChangedListener(mOnHourChangedListener);

        // 初始化分钟选择器
        mMinuteSpinner = (NumberPicker) findViewById(R.id.minute);
        mMinuteSpinner.setMinValue(MINUT_SPINNER_MIN_VAL);
        mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL);
        mMinuteSpinner.setOnLongPressUpdateInterval(100);  // 长按加速间隔
        mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener);

        // 初始化AM/PM选择器（使用本地化字符串）
        String[] ampmStrings = new DateFormatSymbols().getAmPmStrings();
        mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm);
        mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL);
        mAmPmSpinner.setMaxValue(AMPM_SPINNER_MAX_VAL);
        mAmPmSpinner.setDisplayedValues(ampmStrings);
        mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener);

        // 初始化控件状态
        updateDateControl();
        updateHourControl();
        updateAmPmControl();

        // 设置24小时制模式
        set24HourView(is24HourView);

        // 设置当前时间
        setCurrentDate(date);

        // 设置初始启用状态
        setEnabled(DEFAULT_ENABLE_STATE);

        // 初始化完成
        mInitialising = false;
    }

    // 启用/禁用控件
    @Override
    public void setEnabled(boolean enabled) {
        if (mIsEnabled == enabled) return;

        super.setEnabled(enabled);
        mDateSpinner.setEnabled(enabled);
        mMinuteSpinner.setEnabled(enabled);
        mHourSpinner.setEnabled(enabled);
        mAmPmSpinner.setEnabled(enabled);
        mIsEnabled = enabled;
    }

    // 获取当前时间戳
    public long getCurrentDateInTimeMillis() {
        return mDate.getTimeInMillis();
    }

    // 设置当前时间（时间戳）
    public void setCurrentDate(long date) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(date);
        setCurrentDate(
                cal.get(Calendar.YEAR),
                cal.get(Calendar.MONTH),
                cal.get(Calendar.DAY_OF_MONTH),
                cal.get(Calendar.HOUR_OF_DAY),
                cal.get(Calendar.MINUTE)
        );
    }

    // 设置当前时间（各部分）
    public void setCurrentDate(int year, int month, int dayOfMonth,
                               int hourOfDay, int minute) {
        setCurrentYear(year);
        setCurrentMonth(month);
        setCurrentDay(dayOfMonth);
        setCurrentHour(hourOfDay);
        setCurrentMinute(minute);
    }

    // 获取/设置年份
    public int getCurrentYear() { return mDate.get(Calendar.YEAR);  }
    public void setCurrentYear(int year) {
        if (!mInitialising && year == getCurrentYear()) return;
        mDate.set(Calendar.YEAR,  year);
        updateDateControl();
        onDateTimeChanged();
    }

    // 获取/设置月份
    public int getCurrentMonth() { return mDate.get(Calendar.MONTH);  }
    public void setCurrentMonth(int month) {
        if (!mInitialising && month == getCurrentMonth()) return;
        mDate.set(Calendar.MONTH,  month);
        updateDateControl();
        onDateTimeChanged();
    }

    // 获取/设置日
    public int getCurrentDay() { return mDate.get(Calendar.DAY_OF_MONTH);  }
    public void setCurrentDay(int dayOfMonth) {
        if (!mInitialising && dayOfMonth == getCurrentDay()) return;
        mDate.set(Calendar.DAY_OF_MONTH,  dayOfMonth);
        updateDateControl();
        onDateTimeChanged();
    }

    // 获取24小时制小时
    public int getCurrentHourOfDay() {
        return mDate.get(Calendar.HOUR_OF_DAY);
    }

    // 获取当前显示的小时（考虑12/24小时制）
    private int getCurrentHour() {
        if (mIs24HourView){
            return getCurrentHourOfDay();
        } else {
            int hour = getCurrentHourOfDay();
            if (hour > HOURS_IN_HALF_DAY) {
                return hour - HOURS_IN_HALF_DAY;
            } else {
                return hour == 0 ? HOURS_IN_HALF_DAY : hour;
            }
        }
    }

    // 设置小时
    public void setCurrentHour(int hourOfDay) {
        if (!mInitialising && hourOfDay == getCurrentHourOfDay()) return;

        mDate.set(Calendar.HOUR_OF_DAY,  hourOfDay);
        if (!mIs24HourView) {
            // 处理12小时制下的AM/PM状态
            if (hourOfDay >= HOURS_IN_HALF_DAY) {
                mIsAm = false;
                if (hourOfDay > HOURS_IN_HALF_DAY) {
                    hourOfDay -= HOURS_IN_HALF_DAY;
                }
            } else {
                mIsAm = true;
                if (hourOfDay == 0) {
                    hourOfDay = HOURS_IN_HALF_DAY;
                }
            }
            updateAmPmControl();
        }
        mHourSpinner.setValue(hourOfDay);
        onDateTimeChanged();
    }

    // 获取/设置分钟
    public int getCurrentMinute() { return mDate.get(Calendar.MINUTE);  }
    public void setCurrentMinute(int minute) {
        if (!mInitialising && minute == getCurrentMinute()) return;
        mMinuteSpinner.setValue(minute);
        mDate.set(Calendar.MINUTE,  minute);
        onDateTimeChanged();
    }

    // 获取/设置24小时制模式
    public boolean is24HourView() { return mIs24HourView; }
    public void set24HourView(boolean is24HourView) {
        if (mIs24HourView == is24HourView) return;
        mIs24HourView = is24HourView;

        // 更新AM/PM选择器可见性
        mAmPmSpinner.setVisibility(is24HourView  ? View.GONE : View.VISIBLE);

        // 更新小时选择器范围
        updateHourControl();

        // 设置当前小时（保持实际时间不变）
        setCurrentHour(getCurrentHourOfDay());

        // 更新AM/PM显示
        updateAmPmControl();
    }

    // 更新日期控件显示值（一周日期范围）
    private void updateDateControl() {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(mDate.getTimeInMillis());
        cal.add(Calendar.DAY_OF_YEAR,  -DAYS_IN_ALL_WEEK / 2 - 1);

        mDateSpinner.setDisplayedValues(null);
        for (int i = 0; i < DAYS_IN_ALL_WEEK; ++i) {
            cal.add(Calendar.DAY_OF_YEAR,  1);
            // 格式化日期为"MM.dd  EEEE"格式（如"07.15 星期一"）
            mDateDisplayValues[i] = (String) DateFormat.format("MM.dd  EEEE", cal);
        }

        mDateSpinner.setDisplayedValues(mDateDisplayValues);
        mDateSpinner.setValue(DAYS_IN_ALL_WEEK  / 2); // 中间值（当前日）
        mDateSpinner.invalidate();  // 强制重绘
    }

    // 更新AM/PM控件状态
    private void updateAmPmControl() {
        if (mIs24HourView) {
            mAmPmSpinner.setVisibility(View.GONE);
        } else {
            int index = mIsAm ? Calendar.AM : Calendar.PM;
            mAmPmSpinner.setValue(index);
            mAmPmSpinner.setVisibility(View.VISIBLE);
        }
    }

    // 更新小时控件范围（12/24小时制）
    private void updateHourControl() {
        if (mIs24HourView) {
            mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW);
            mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW);
        } else {
            mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW);
            mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW);
        }
    }

    // 设置日期时间变化监听器
    public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback) {
        mOnDateTimeChangedListener = callback;
    }

    // 触发日期时间变化回调
    private void onDateTimeChanged() {
        if (mOnDateTimeChangedListener != null) {
            mOnDateTimeChangedListener.onDateTimeChanged(this,
                    getCurrentYear(), getCurrentMonth(), getCurrentDay(),
                    getCurrentHourOfDay(), getCurrentMinute());
        }
    }
}
