package netmanager.common;

import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.ActionEvent;
import java.awt.*;
import java.util.Calendar;
import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.io.Serializable;


public class JDateChooser extends JPanel implements ActionListener, ChangeListener, Serializable {
    private static final long serialVersionUID = 1L;
    private int width = 300;    
    private int height = 200;   
    private Color backGroundColor = Color.gray;     
    private Color palletTableColor = Color.white;   
    private Color todayBackColor = Color.GREEN;     
    private Color weekFontColor = Color.blue;      
    private Color dateFontColor = Color.black;      
    private Color weekendFontColor = Color.red;    
    private Color controlLineColor = Color.LIGHT_GRAY;    
    private Color controlTextColor = Color.black; 
    private JDialog dialog;
    private JSpinner yearSpin;
    private JSpinner monthSpin;
    private JSpinner hourSpin;
    private JSpinner minuteSpin;
    private JButton[][] daysButton = new JButton[6][7];
    private JFormattedTextField jFormattedTextField;
    private Calendar c = getCalendar();
    private String format = "yyyy-MM-dd";
    private String JDialogName = "";
    private int startYear = 1900;
    private int lastYear = 2900;
    
    public JDateChooser(JFormattedTextField jftf, int controlStyle) 
    {
        jFormattedTextField = jftf;
        setLayout(new BorderLayout());
        setBorder(new LineBorder(backGroundColor, 2));
        setBackground(backGroundColor);
        JPanel topYearAndMonth = initYearAndMonthPanal(controlStyle);
        add(topYearAndMonth, BorderLayout.NORTH);
        JPanel centerWeekAndDay = initWeekAndDayPanal();
        add(centerWeekAndDay, BorderLayout.CENTER);
    }
    
    private JPanel initYearAndMonthPanal(int controlStyle) {
        int currentYear = c.get(Calendar.YEAR);
        int currentMonth = c.get(Calendar.MONTH) + 1;
        int currentHour = c.get(Calendar.HOUR_OF_DAY);
        int currentMinute = c.get(Calendar.MINUTE);

        JPanel result = new JPanel();
        result.setLayout(new FlowLayout());
        result.setBackground(controlLineColor);

        yearSpin = new JSpinner(new SpinnerNumberModel(currentYear, this.getStartYear(), this.getLastYear(), 1));
        yearSpin.setPreferredSize(new Dimension(48, 20));
        yearSpin.setName("Year");
        yearSpin.setEditor(new JSpinner.NumberEditor(yearSpin, "####"));
        yearSpin.addChangeListener(this);
        result.add(yearSpin);

        JLabel yearLabel = new JLabel("年");
        yearLabel.setForeground(controlTextColor);
        result.add(yearLabel);

        monthSpin = new JSpinner(new SpinnerNumberModel(currentMonth, 1, 12, 1));
        monthSpin.setPreferredSize(new Dimension(35, 20));
        monthSpin.setName("Month");
        monthSpin.addChangeListener(this);
        result.add(monthSpin);

        JLabel monthLabel = new JLabel("月");
        monthLabel.setForeground(controlTextColor);
        result.add(monthLabel);

        if (controlStyle > 0) {
            hourSpin = new JSpinner(new SpinnerNumberModel(currentHour, 0, 23, 1));
            hourSpin.setPreferredSize(new Dimension(35, 20));
            hourSpin.setName("Hour");
            hourSpin.addChangeListener(this);
            result.add(hourSpin);

            JLabel hourLabel = new JLabel("时");
            hourLabel.setForeground(controlTextColor);
            result.add(hourLabel);
        }
        if (controlStyle > 1) {
            minuteSpin = new JSpinner(new SpinnerNumberModel(currentMinute, 0, 59, 1));
            minuteSpin.setPreferredSize(new Dimension(35, 20));
            minuteSpin.setName("Minute");
            minuteSpin.addChangeListener(this);
            result.add(minuteSpin);

            JLabel minuteLabel = new JLabel("分");
            minuteLabel.setForeground(controlTextColor);
            result.add(minuteLabel);
        }

        return result;
    }

    private JPanel initWeekAndDayPanal() {
        String colname[] = {"日", "一", "二", "三", "四", "五", "六"};
        JPanel result = new JPanel();
        
        result.setLayout(new GridLayout(7, 7));
        result.setBackground(Color.white);
        JLabel cell;

        for (int i = 0; i < 7; i++) {
            cell = new JLabel(colname[i]);
            cell.setHorizontalAlignment(JLabel.CENTER);
            if (i == 0 || i == 6) {
                cell.setForeground(weekendFontColor);
            } else {
                cell.setForeground(weekFontColor);
            }
            result.add(cell);
        }

        int actionCommandId = 0;
        for (int i = 0; i < 6; i++)
            for (int j = 0; j < 7; j++) {
                JButton numberButton = new JButton();
                numberButton.setBorder(null);
                numberButton.setHorizontalAlignment(SwingConstants.CENTER);
                numberButton.setActionCommand(String.valueOf(actionCommandId));
                numberButton.addActionListener(this);
                numberButton.setBackground(palletTableColor);
                numberButton.setForeground(dateFontColor);
                if (j == 0 || j == 6) {
                    numberButton.setForeground(weekendFontColor);
                } else {
                    numberButton.setForeground(dateFontColor);
                }
                daysButton[i][j] = numberButton;
                numberButton.addMouseListener(new MouseAdapter() {
                    public void mouseClicked(MouseEvent e) {
                        if (e.getClickCount() == 2) {
                            closeAndSetDate();
                        }
                    }
                });
                result.add(numberButton);
                actionCommandId++;
            }

        return result;
    }

    public void showDateChooser(Point position) {
        Object tmpobj = SwingUtilities.getWindowAncestor(jFormattedTextField);
        if (tmpobj.getClass().isInstance(new JDialog()) || tmpobj.getClass().getSuperclass().isInstance(new JDialog())) {
            JDialog ownerdialog = (JDialog) SwingUtilities.getWindowAncestor(jFormattedTextField);
            if (dialog == null || dialog.getOwner() != ownerdialog) {
                dialog = initDialog(ownerdialog);
            }
            dialog.setLocation(getAppropriateLocation(ownerdialog, position));
        } else if (tmpobj.getClass().isInstance(new JFrame()) || tmpobj.getClass().getSuperclass().isInstance(new JFrame())) {
            JFrame ownerFrame = (JFrame) SwingUtilities.getWindowAncestor(jFormattedTextField);
            if (dialog == null || dialog.getOwner() != ownerFrame) {
                dialog = initDialog(ownerFrame);
            }
            dialog.setLocation(getAppropriateLocation(ownerFrame, position));
        }

        initWeekAndDay();
        dialog.setVisible(true);
    }

    private JDialog initDialog(JDialog owner) {
        JDialog result = new JDialog(owner, this.getJDialogName(), true);
        result.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
        result.getContentPane().add(this, BorderLayout.CENTER);
        result.pack();
        result.setSize(width, height);
        return result;
    }
    
    private JDialog initDialog(JFrame owner) {
        JDialog result = new JDialog(owner, this.getJDialogName(), true);
        result.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
        result.getContentPane().add(this, BorderLayout.CENTER);
        result.pack();
        result.setSize(width, height);
        return result;
    }

    private Point getAppropriateLocation(JDialog owner, Point position) {
        Point result = new Point(position);
        Point p = owner.getLocation();
        int offsetX = (position.x + width) - (p.x + owner.getWidth());
        int offsetY = (position.y + height) - (p.y + owner.getHeight());

        if (offsetX > 0) {
            result.x -= offsetX;
        }

        if (offsetY > 0) {
            result.y -= offsetY;
        }

        return result;
    }
    
    private Point getAppropriateLocation(JFrame owner, Point position) {
        Point result = new Point(position);
        Point p = owner.getLocation();
        int offsetX = (position.x + width) - (p.x + owner.getWidth());
        int offsetY = (position.y + height) - (p.y + owner.getHeight());

        if (offsetX > 0) {
            result.x -= offsetX;
        }

        if (offsetY > 0) {
            result.y -= offsetY;
        }

        return result;
    }
    
    public void closeAndSetDate() {
        setDate(c.getTime());
        dialog.dispose();
    }

    private Calendar getCalendar() {
        Calendar result = Calendar.getInstance();
        result.setTime(getDate());
        return result;
    }

    private void initWeekAndDay() {
        c.set(Calendar.DAY_OF_MONTH, 1);
        int maxDayNo = c.getActualMaximum(Calendar.DAY_OF_MONTH);
        int dayNo = 2 - c.get(Calendar.DAY_OF_WEEK);
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 7; j++) {
                if (dayNo >= 1 && dayNo <= maxDayNo) {
                    String s = String.valueOf(dayNo);
                    daysButton[i][j].setVisible(true);
                    daysButton[i][j].setText(s);
                } else {
                    daysButton[i][j].setVisible(false);
                }
                dayNo++;
            }
        }
        dayColorUpdate(false);
    }

    private void dayColorUpdate(boolean isOldDay) {
        int day = c.get(Calendar.DAY_OF_MONTH);
        c.set(Calendar.DAY_OF_MONTH, 1);
        int actionCommandId = day - 2 + c.get(Calendar.DAY_OF_WEEK);
        int i = actionCommandId / 7;
        int j = actionCommandId % 7;
        if (isOldDay) {
            daysButton[i][j].setForeground(dateFontColor);
        } else {
            daysButton[i][j].setForeground(todayBackColor);
        }
    }

    public void stateChanged(ChangeEvent e) {
        JSpinner source = (JSpinner) e.getSource();

        if (source.getName().equals("Minute")) {
            c.set(Calendar.MINUTE, getSelectedMinute());
            return;
        }
        if (source.getName().equals("Hour")) {
            c.set(Calendar.HOUR_OF_DAY, getSelectedHour());
            return;
        }
        dayColorUpdate(true);
        if (source.getName().equals("Year")) {
            c.set(Calendar.YEAR, getSelectedYear());
        }
        if (source.getName().equals("Month")) {
            c.set(Calendar.MONTH, getSelectedMonth() - 1);
        }

        initWeekAndDay();
    }

    private int getSelectedYear() {
        return ((Integer) yearSpin.getValue()).intValue();
    }

    private int getSelectedMonth() {
        return ((Integer) monthSpin.getValue()).intValue();
    }

    private int getSelectedHour() {
        return ((Integer) hourSpin.getValue()).intValue();
    }

    private int getSelectedMinute() {
        return ((Integer) minuteSpin.getValue()).intValue();
    }

    public void actionPerformed(ActionEvent e) {
        JButton source = (JButton) e.getSource();
        if (source.getText().length() == 0) {
            return;
        }
        dayColorUpdate(true);
        source.setForeground(todayBackColor);
        int newDay = Integer.parseInt(source.getText());
        c.set(Calendar.DAY_OF_MONTH, newDay);

    }

    public void setDate(Date date) {
        jFormattedTextField.setText(getDefaultDateFormat().format(date));
    }

    public Date getDate() {
        try {
            String dateString = jFormattedTextField.getText();
            return getDefaultDateFormat().parse(dateString);
        } catch (ParseException e) {
            return getNowDate();
        } catch (Exception ee) {
            return getNowDate();
        }
    }

    private static Date getNowDate() {
        return Calendar.getInstance().getTime();
    }

    private SimpleDateFormat getDefaultDateFormat() {
        return new SimpleDateFormat(this.getFormat());
    }

    public int getLastYear() {
        return lastYear;
    }

    public void setLastYear(int lastYear) {
        this.lastYear = lastYear;
    }

    public int getStartYear() {
        return startYear;
    }

    public void setStartYear(int startYear) {
        this.startYear = startYear;
    }

    public String getFormat() {
        return format;
    }

    public void setFormat(String format) {
        this.format = format;
    }

    public String getJDialogName() {
        return JDialogName;
    }

    public void setJDialogName(String JDialogName) {
        this.JDialogName = JDialogName;
    }
}
