/****************************************************************************
 * Copyright (c) 2008 Jeremy Dowdall
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 * 
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *    Jeremy Dowdall <[email protected]> - initial API and implementation
 *****************************************************************************/

package org.eclipse.nebula.widgets.cdatetime;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;

import org.eclipse.nebula.cwt.v.VButton;
import org.eclipse.nebula.cwt.v.VControl;
import org.eclipse.nebula.cwt.v.VGridLayout;
import org.eclipse.nebula.cwt.v.VLabel;
import org.eclipse.nebula.cwt.v.VNative;
import org.eclipse.nebula.cwt.v.VPanel;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;

public class CDatePanel extends Composite {

	private VPanel panel;
	private VPanel header;
	private VPanel body;
	private List<VNative<CDateTime>> pickers;
	private int headerSize;
	private int pickerSize;

	private CDateTimeBuilder builder;
	private CDateTimePainter painter;

	private Locale locale;
	private TimeZone timezone;
	private Calendar calendar;

	private SelectionAdapter listener = new SelectionAdapter() {
		@Override
		public void widgetDefaultSelected(SelectionEvent e) {
			CDateTime cdt = (CDateTime) e.widget;
			for (VNative<CDateTime> picker : pickers) {
				if (picker.getControl() != e.widget) {
					picker.getControl().setSelection(cdt.getSelection());
				}
			}
		}
	};

	public CDatePanel(Composite parent, int style) {
		super(parent, style);

		panel = new VPanel(this, SWT.NONE);

		locale = Locale.getDefault();
		try {
			timezone = TimeZone.getDefault();
		} catch (Exception e) {
			timezone = TimeZone.getTimeZone("GMT");
		}
		calendar = Calendar.getInstance(this.timezone, this.locale);
		calendar.setTime(new Date());

		builder = new CDateTimeBuilder();
		builder.setHeader(
				Header.Month().align(SWT.RIGHT, SWT.FILL, true).readOnly(),
				Header.Year().align(SWT.LEFT, SWT.FILL, true).readOnly());
		builder.setBody(Body.Days().compact());

		painter = new CDateTimePainter() {
			@Override
			protected void paintDayPanelBorders(VControl control, Event e) {
				Rectangle r = control.getBounds();
				e.gc.setForeground(e.display
						.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
				e.gc.drawLine(r.x, r.y, r.x, r.y + r.height - 50);
				e.gc.drawLine(r.x + r.width - 1, r.y, r.x + r.width - 1,
						r.y + r.height - 1);
				e.gc.drawLine(r.x, r.y + r.height - 1, r.x + r.width - 1,
						r.y + r.height - 1);
			}
		};

		pickers = new ArrayList<>();
		pickerSize = -1;

		VGridLayout layout = new VGridLayout();
		layout.verticalSpacing = 2;
		panel.setLayout(layout);

		createHeader();

		VLabel sep = new VLabel(panel, SWT.HORIZONTAL | SWT.SEPARATOR);
		sep.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));

		body = new VPanel(panel, SWT.NONE);
		body.setLayout(new VGridLayout());
		body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

		body.addListener(SWT.Resize, event -> handleResize());
	}

	private void addMonth() {
		VNative<CDateTime> picker = VNative.create(CDateTime.class, body,
				CDT.MULTI | CDT.SIMPLE);
		picker.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));

		CDateTime cdt = picker.getControl();
		cdt.setBuilder(builder);
		cdt.setPainter(painter);
		cdt.setPattern("MMMM d yyyy");
		cdt.setLocale(locale);
		cdt.setTimeZone(timezone);
		cdt.setScrollable(false);
		cdt.addSelectionListener(listener);

		pickers.add(picker);

		updateMonths();
	}

	private void createHeader() {
		header = new VPanel(panel, SWT.NONE);
		VGridLayout layout = new VGridLayout(3, true);
		layout.marginWidth = 0;
		layout.marginHeight = 0;
		header.setLayout(layout);
		header.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));

		VButton b = new VButton(header, SWT.ARROW | SWT.LEFT | SWT.NO_FOCUS);
		b.setFill(getDisplay().getSystemColor(SWT.COLOR_GRAY));
		b.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
		b.addListener(SWT.Selection, event -> {
			calendar.add(Calendar.MONTH, -1);
			updateMonths();
		});

		b = new VButton(header, SWT.PUSH | SWT.NO_FOCUS);
		b.setText("Today");
		b.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		b.addListener(SWT.Selection, event -> {
			calendar.setTimeInMillis(System.currentTimeMillis());
			updateMonths();
		});

		b = new VButton(header, SWT.ARROW | SWT.RIGHT | SWT.NO_FOCUS);
		b.setFill(getDisplay().getSystemColor(SWT.COLOR_GRAY));
		b.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
		b.addListener(SWT.Selection, event -> {
			calendar.add(Calendar.MONTH, 1);
			updateMonths();
		});

		headerSize = header.computeSize(-1, -1).y;
	}

	public VPanel getPanel() {
		return panel;
	}

	private void handleResize() {
		if (pickerSize == -1) {
			setMonthCount(1);
			pickerSize = pickers.get(0).computeSize(-1, -1).y;
		}

		int height = getClientArea().height;
		int count = (int) Math
				.ceil((double) (height - headerSize) / pickerSize);

		setMonthCount(count);
	}

	private void removeMonth() {
		if (!pickers.isEmpty()) {
			VNative<CDateTime> picker = pickers.remove(pickers.size() - 1);
			picker.dispose();
		}
	}

	public void setMonthCount(int count) {
		while (count > pickers.size()) {
			addMonth();
		}
		while (count < pickers.size()) {
			removeMonth();
		}
	}

	private void updateMonths() {
		Calendar tmpcal = Calendar.getInstance(timezone, locale);
		tmpcal.setTime(calendar.getTime());
		for (VNative<CDateTime> picker : pickers) {
			picker.getControl().show(tmpcal.getTime());
			tmpcal.add(Calendar.MONTH, 1);
		}
	}

}