/**
 * 文件名称：DateTimePicker.java
 * 版权声明：版权所有 (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
 * 许可证声明：根据Apache License, Version 2.0（“许可证”）获得许可；
 * 除非遵守许可证，否则不得使用此文件。
 * 您可以在以下网址获得许可证的副本：
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * 除非适用法律要求或书面同意，否则按“现状”分发的软件是在没有任何明示或暗示的
 * 保证和条件的情况下提供的，包括但不限于关于所有权、不侵犯第三方权利、适销性或
 * 适用于特定用途的任何保证和条件。有关权限和限制的具体语言，请参见许可证。
 */

package net.micode.notes.ui; // 定义包名

import java.text.DateFormatSymbols; // 用于日期时间格式化的符号
import java.util.Calendar; // 用于日期时间操作的日历类

import net.micode.notes.R; // 导入资源文件R，用于访问资源

import android.content.Context; // Android上下文环境
import android.text.format.DateFormat; // 用于日期时间格式化
import android.view.View; // 用于视图操作
import android.widget.FrameLayout; // 布局容器FrameLayout
import android.widget.NumberPicker; // 自定义视图，用于选择数字

/**
 * DateTimePicker 类是一个自定义视图组件，用于在Android应用中选择日期和时间。
 */
public class DateTimePicker extends FrameLayout {
    // 类成员变量声明
    private static final boolean DEFAULT_ENABLE_STATE = true; // 默认启用状态

    // 时间单位常量
    private static final int HOURS_IN_HALF_DAY = 12;
    private static final int HOURS_IN_ALL_DAY = 24;
    private static final int DAYS_IN_ALL_WEEK = 7;
    // NumberPicker组件的值范围常量
    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; // 用于选择日期的NumberPicker
    private final NumberPicker mHourSpinner; // 用于选择小时的NumberPicker
    private final NumberPicker mMinuteSpinner; // 用于选择分钟的NumberPicker
    private final NumberPicker mAmPmSpinner; // 用于选择上午/下午的NumberPicker
    private Calendar mDate; // 用于管理日期和时间的Calendar实例

    // 日期显示值数组
    private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK];

    // 上午/下午状态标志
    private boolean mIsAm;

    // 是否为24小时视图
    private boolean mIs24HourView;

    // 控件启用状态
    private boolean mIsEnabled = DEFAULT_ENABLE_STATE;

    // 控件初始化状态
    private boolean mInitialising;

    // 日期时间改变监听器
    private OnDateTimeChangedListener mOnDateTimeChangedListener;

    // NumberPicker值变化监听器
    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();
        }
    };

    // 小时变化监听器
    private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() {
        @Override
        public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
            // 当小时值变化时，更新日历并通知监听器
            boolean isDateChanged = false;
            Calendar cal = Calendar.getInstance();
            if (!mIs24HourView) {
                // 处理12小时制逻辑
                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;
                } 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;
                }
                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();
                }
            } else {
                // 处理24小时制逻辑
                if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) {
                    cal.setTimeInMillis(mDate.getTimeInMillis());
                    cal.add(Calendar.DAY_OF_YEAR, 1);
                    isDateChanged = true;
                } else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {
                    cal.setTimeInMillis(mDate.getTimeInMillis());
                    cal.add(Calendar.DAY_OF_YEAR, -1);
                    isDateChanged = true;
                }
            }
            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));
            }
        }
    };

    // 分钟变化监听器
    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();
                int newHour = getCurrentHourOfDay();
                if (newHour >= HOURS_IN_HALF_DAY) {
                    mIsAm = false;
                    updateAmPmControl();
                } else {
                    mIsAm = true;
                    updateAmPmControl();
                }
            }
            mDate.set(Calendar.MINUTE, newVal);
            onDateTimeChanged();
        }
    };

    // 上午/下午变化监听器
    private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {
        @Override
        public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
            // 当上午/下午变化时，更新日历并通知监听器
            mIsAm = !mIsAm;
            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);
    }

    // DateTimePicker的构造函数
    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

	String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings();
    	mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm);
    	mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL);
    	mAmPmSpinner.setMaxValue(AMPM_SPINNER_MAX_VAL);
    	mAmPmSpinner.setDisplayedValues(stringsForAmPm);
    	mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener);

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

    	set24HourView(is24HourView);

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

    	setEnabled(isEnabled());

    	// 设置内容描述
    	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;
}

@Override
public boolean isEnabled() {
    // 获取控件是否可用
    return mIsEnabled;
}

/**
 * 获取当前日期的毫秒值
 *
 * @return 当前日期的毫秒值
 */
public long getCurrentDateInTimeMillis() {
    return mDate.getTimeInMillis();
}

/**
 * 设置当前日期
 *
 * @param date 当前日期的毫秒值
 */
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));
}

/**
 * 设置当前日期
 *
 * @param year 当前年
 * @param month 当前月
 * @param dayOfMonth 当前日
 * @param hourOfDay 当前小时
 * @param minute 当前分钟
 */
public void setCurrentDate(int year, int month,
        int dayOfMonth, int hourOfDay, int minute) {
    setCurrentYear(year);
    setCurrentMonth(month);
    setCurrentDay(dayOfMonth);
    setCurrentHour(hourOfDay);
    setCurrentMinute(minute);
}

/**
 * 获取当前年份
 *
 * @return 当前年份
 */
public int getCurrentYear() {
    return mDate.get(Calendar.YEAR);
}

/**
 * 设置当前年份
 *
 * @param year 当前年份
 */
public void setCurrentYear(int year) {
    if (!mInitialising && year == getCurrentYear()) {
        return;
    }
    mDate.set(Calendar.YEAR, year);
    updateDateControl();
    onDateTimeChanged();
}

/**
 * 获取当前月份
 *
 * @return 当前月份
 */
public int getCurrentMonth() {
    return mDate.get(Calendar.MONTH);
}

/**
 * 设置当前月份
 *
 * @param month 月份
 */
public void setCurrentMonth(int month) {
    if (!mInitialising && month == getCurrentMonth()) {
        return;
    }
    mDate.set(Calendar.MONTH, month);
    updateDateControl();
    onDateTimeChanged();
}

/**
 * 获取当前月份中的日期
 *
 * @return 月份中的日期
 */
public int getCurrentDay() {
    return mDate.get(Calendar.DAY_OF_MONTH);
}

/**
 * 设置当前月份中的日期
 *
 * @param dayOfMonth 月份中的日期
 */
public void setCurrentDay(int dayOfMonth) {
    if (!mInitialising && dayOfMonth == getCurrentDay()) {
        return;
    }
    mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
    updateDateControl();
    onDateTimeChanged();
}

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

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;
        }
    }
}

/**
 * 设置24小时制的当前小时
 *
 * @param hourOfDay 24小时制的小时
 */
public void setCurrentHour(int hourOfDay) {
    if (!mInitialising && hourOfDay == getCurrentHourOfDay()) {
        return;
    }
    mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
    if (!mIs24HourView) {
        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();
}

/**
 * 获取当前分钟
 *
 * @return 当前分钟
 */
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小时视图
 *
 * @return 如果是24小时视图返回true，否则返回false。
 */
public boolean is24HourView () {
    return mIs24HourView;
}

/**
 * 设置是否是24小时视图或AM/PM模式
 *
 * @param is24HourView 如果是24小时视图传入true，否则传入false。
 */
public void set24HourView(boolean is24HourView) {
    if (mIs24HourView == is24HourView) {
        return;
    }
    mIs24HourView = is24HourView;
    mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE);
    int hour = getCurrentHourOfDay();
    updateHourControl();
    setCurrentHour(hour);
    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);
        mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal);
    }
    mDateSpinner.setDisplayedValues(mDateDisplayValues);
    mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2);
    mDateSpinner.invalidate();
}

/**
 * 更新上午/下午控制
 */
private void updateAmPmControl() {
    if (mIs24HourView) {
        mAmPmSpinner.setVisibility(View.GONE); // 在24小时视图中隐藏AM/PM选择器
    } else {
        int index = mIsAm ? Calendar.AM : Calendar.PM; // 根据当前时间是上午还是下午设置索引
        mAmPmSpinner.setValue(index); // 设置AM/PM选择器的值
        mAmPmSpinner.setVisibility(View.VISIBLE); // 显示AM/PM选择器
    }
}

/**
 * 更新小时控制
 */
private void updateHourControl() {
    if (mIs24HourView) {
        mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW); // 设置24小时视图的小时最小值
        mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW); // 设置24小时视图的小时最大值
    } else {
        mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW); // 设置12小时视图的小时最小值
        mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW); // 设置12小时视图的小时最大值
    }
}

/**
 * 设置日期时间改变的监听器
 *
/**
 * 当日期时间改变时调用此方法
 */
private void onDateTimeChanged() {
    if (mOnDateTimeChangedListener != null) {
        mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(),
                getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute());
    }
}