/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package view.tool.dateField;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JSpinner.DefaultEditor;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import view.Vue;

/**
 *
 * @author alexis
 */
public class DatePanel extends Vue implements ChangeListener, ActionListener {
	/*properties*/
	private static final long serialVersionUID = 5605935834677678561L;
	
	private final boolean isEditable;
    private final int startYear = 1980;
    private final int lastYear = 2100;

    private final Color backGroundColor = Color.gray;
    private final Color palletTableColor = Color.white;
    private final Color todayBackColor = Color.orange;
    private final Color weekFontColor = Color.blue;
    private final Color dateFontColor = Color.black;
    private final Color weekendFontColor = Color.red;

    private final Color controlLineColor = Color.blue;
    private final Color controlTextColor = Color.white;

    /*composition*/
    private JSpinner yearSpin;
    private JSpinner monthSpin;
    private JButton[][] daysButton = new JButton[6][7];
    private JLabel month = new JLabel();
    private Calendar cal;
    private Calendar lastSelected;
    
    /*constructeur*/
    /**constructeur privée
     * @param _isEditable as bool
     * @param _cal as Calendar
     */
    private DatePanel(boolean _isEditable, Calendar _cal){
        isEditable = _isEditable;
        cal = _cal;
        lastSelected = (Calendar)cal.clone();
        
        initComponents();
    }
    
    /*static factory*/
    /**
     * static factory
     * calendrier swing editable avec date
     * @param _cal as Calendar
     * @return DatePanel
     */
    public static DatePanel DatePanelEditableAtDate(Calendar _cal){
        return new DatePanel(true,_cal);
    }
    
    /**
     * static factory
     * calendrier swing editable à la date courante
     * @return DatePanel
     */
    public static DatePanel DatePanelEditableAtCurrentDate(){
        return new DatePanel(true,Calendar.getInstance());
    }
    
    /**
     * static factory
     * calendrier swing non editable avec date
     * @param _cal as Calendar
     * @return DatePanel
     */
    public static DatePanel DatePanelAtDate(Calendar _cal){
        return new DatePanel(false,_cal);
    }
    
    /**
     * static factory
     * calendrier swing non editable à la date actuele
     * @return DatePanel
     */
    public static DatePanel DatePanelAtCurrentDate(){
        return new DatePanel(false,Calendar.getInstance());
    }
    
    /*methode privée*/
    /**
     * private method
     * produire l'interface graphique swing
     */
    private void initComponents(){
        month.setHorizontalAlignment(SwingConstants.CENTER);
        setLayout(new BorderLayout());
        setBorder(new LineBorder(backGroundColor, 2));
        setBackground(backGroundColor);

        JPanel topYearAndMonth = createYearAndMonthPanal();
        add(topYearAndMonth, BorderLayout.NORTH);
        JPanel centerWeekAndDay = createWeekAndDayPanal();
        add(centerWeekAndDay, BorderLayout.CENTER);

        reflushWeekAndDay();
        setDayToColor(cal.get(Calendar.DAY_OF_MONTH),todayBackColor);
    }
    
    /**
     * private setter
     * la couleur de la journée
     * @param day as int
     * @param color as Color
     */
    private void setDayToColor(int day, Color color){
        cal.set(Calendar.DAY_OF_MONTH, 1);
        int actionCommandId = day - 2 + cal.get(Calendar.DAY_OF_WEEK);
        int i = actionCommandId / 7;
        int j = actionCommandId % 7;
        
        daysButton[i][j].setForeground(color);
        cal.set(Calendar.DAY_OF_MONTH, day);
    }

    /**
     * private factory
     * un panneau selecteur pour l'année et le moi
     * @return JPanel
     */
    private JPanel createYearAndMonthPanal() {
        int currentYear = cal.get(Calendar.YEAR);
        int currentMonth = cal.get(Calendar.MONTH) + 1;
        month.setText(getMonthInWord(cal.get(Calendar.MONTH) + 1));

        JPanel splitPanel = new JPanel();
        splitPanel.setLayout(new BorderLayout());
        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout());
        panel.setBackground(controlLineColor);

        yearSpin = new JSpinner(new SpinnerNumberModel(currentYear,startYear, lastYear, 1));
        yearSpin.setPreferredSize(new Dimension(56, 20));
        yearSpin.setName("Year");
        yearSpin.setEditor(new JSpinner.NumberEditor(yearSpin, "####"));
        ((DefaultEditor) yearSpin.getEditor()).getTextField().setEditable(false);
        if(isEditable)
            yearSpin.addChangeListener(this);
        else
            yearSpin.setEnabled(false);
        panel.add(yearSpin);

        JLabel yearLabel = new JLabel("Year");
        yearLabel.setForeground(controlTextColor);
        panel.add(yearLabel);

        monthSpin = new JSpinner(new SpinnerNumberModel(currentMonth, 1,
                12, 1));
        monthSpin.setPreferredSize(new Dimension(35, 20));
        monthSpin.setName("Month");
        ((DefaultEditor) monthSpin.getEditor()).getTextField().setEditable(false);
        if(isEditable)
            monthSpin.addChangeListener(this);
        else
            monthSpin.setEnabled(false);
        
        panel.add(monthSpin);

        JLabel monthLabel = new JLabel("Month");
        monthLabel.setForeground(controlTextColor);
        panel.add(monthLabel);

        splitPanel.add(panel,BorderLayout.NORTH);
        splitPanel.add(month,BorderLayout.CENTER);

        return splitPanel;
    }

    /**
     * private factory
     * entète du calendrier
     * @return JPanel
     */
    private JPanel createWeekAndDayPanal() {
        String colname[] = { "D ", "L ", "M ", "M ", "J ", "V ", "S " };
        Border dayBorder = new LineBorder(Color.BLACK, 1);
        JPanel panel = new JPanel();
        panel.setFont(new Font("Arial", Font.PLAIN, 10));
        panel.setLayout(new GridLayout(7, 7));
        panel.setBackground(Color.white);

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

        int actionCommandId = 0;
        for (int i = 0; i < 6; i++)
            for (int j = 0; j < 7; j++) {
                JButton numBtn = new JButton();
                numBtn.setBorder(null);
                numBtn.setHorizontalAlignment(SwingConstants.RIGHT);
                numBtn.setActionCommand(String
                        .valueOf(actionCommandId));
                numBtn.setBackground(palletTableColor);
                numBtn.setForeground(dateFontColor);
                if(isEditable)
                    numBtn.addActionListener(this);

                if (j == 0 || j == 6)
                    numBtn.setForeground(weekendFontColor);
                else
                    numBtn.setForeground(dateFontColor);
                
                numBtn.setBorder(dayBorder);
                daysButton[i][j] = numBtn;
                panel.add(numBtn);
                actionCommandId++;
            }

        return panel;
    }

    /**
     * private getter
     * obtenir le moi du jours
     * @param monthNumber as int
     * @return nom du moi as String
     */
    private String getMonthInWord(int monthNumber){
        switch(monthNumber)
        {
            case 1: return "Janvier";
            case 2: return "Février";
            case 3: return "Mars";
            case 4: return "Avril";
            case 5: return "Mai";
            case 6: return "Juin";
            case 7: return "Juillet";
            case 8: return "Août";
            case 9: return "Septembre";
            case 10: return "Octobre";
            case 11: return "Novembre";
            case 12: return "Décembre";
        }

        return "ERROR";
    }

    /**
     * private getter
     * année selectionné
     * @return int
     */
    private int getSelectedYear() {
        return ((Integer) yearSpin.getValue()).intValue();
    }

    /**
     * private getter
     * moi selectionné
     * @return int
     */
    private int getSelectedMonth() {
        return ((Integer) monthSpin.getValue()).intValue();
    }

    /**
     * private method
     *  changer la couleur du jour courant
     */
    private void dayColorUpdate() {
        int day = cal.get(Calendar.DAY_OF_MONTH);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        int actionCommandId = day - 2 + cal.get(Calendar.DAY_OF_WEEK);
        int i = actionCommandId / 7;
        int j = actionCommandId % 7;
        
        if (j == 0 || j == 6) {
            daysButton[i][j].setForeground(weekendFontColor);
        } else {
            daysButton[i][j].setForeground(dateFontColor);
        }
        cal.set(Calendar.DAY_OF_MONTH,day);
    }

    /**
     * pivate method
     * reset le calendrier
     */
    private void reflushWeekAndDay() {
        int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        int maxDayNo = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        int dayNo = 2 - cal.get(Calendar.DAY_OF_WEEK);
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 7; j++) {
                String s = "";
                if (dayNo >= 1 && dayNo <= maxDayNo) {
                    s = String.valueOf(dayNo);
                }
                daysButton[i][j].setText(s);
                dayNo++;
            }
        }
        cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        dayColorUpdate();
    }
    
    /**
     * getter
     * obtenir la date choisie
     * @return Calendar
     */
    public Calendar getCalendar(){
        return lastSelected;
    }

    /*setter*/
    /**
     * setter
     * modifier le calendrier
     * @param _cal as Calendar
     */
    public void setCalendar(Calendar _cal){
        cal = _cal;
        lastSelected = (Calendar) _cal.clone();
        reflushWeekAndDay();
    }
    
    /*implement action listener*/
    @Override
    public void actionPerformed(ActionEvent event) {
        JButton source = (JButton) event.getSource();

        if (source.getText().length() != 0) 
        {
            setDayToColor(cal.get(Calendar.DAY_OF_MONTH),dateFontColor);

            source.setForeground(todayBackColor);
            int newDay = Integer.parseInt(source.getText());
            cal.set(Calendar.DAY_OF_MONTH, newDay);
            lastSelected = (Calendar) cal.clone();
            this.getObservable().notifyObservers(cal);
        }
    }

    /*implements changeListener*/
    @Override
    public void stateChanged(ChangeEvent e) {
        dayColorUpdate();

        JSpinner source = (JSpinner) e.getSource();
        if (source.getName().equals("Year")) {
            cal.set(Calendar.YEAR, getSelectedYear());
        } else {
            cal.set(Calendar.MONTH, getSelectedMonth() - 1);
        }
        
        month.setText(getMonthInWord(getSelectedMonth()));
        reflushWeekAndDay();
        
        if((Integer)yearSpin.getValue() == lastSelected.get(Calendar.YEAR))
        {
            if((Integer)monthSpin.getValue()-1 == lastSelected.get(Calendar.MONTH))
            {
                setDayToColor(lastSelected.get(Calendar.DAY_OF_MONTH),todayBackColor);
            }
        }
    }
}