package charactermanaj.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.EventObject;
import java.util.LinkedList;
import java.util.Properties;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.Timer;

import charactermanaj.model.AppConfig;
import charactermanaj.util.LocalizedResourcePropertyLoader;
import charactermanaj.util.UIUtility;

/**
 * プレビューパネル
 * @author seraphy
 */
public class PreviewPanel extends JPanel {

	private static final long serialVersionUID = 1L;

	protected static final String STRINGS_RESOURCE = "strings/previewpanel";
	
	public interface PreviewPanelListener {
		
		void savePicture(PreviewPanelEvent e);
		
		void copyPicture(PreviewPanelEvent e);

		void changeBackgroundColor(PreviewPanelEvent e);

		void showInformation(PreviewPanelEvent e);

		void addFavorite(PreviewPanelEvent e);
		
		void flipHorizontal(PreviewPanelEvent e);
	}

	private final long indicatorDelay;
	
	private final String indicatorText;
	
	private final Timer timer = new Timer(100, new ActionListener() {
		public void actionPerformed(ActionEvent e) {
			onTimer();
		}
	});
	
	@Override
	public void addNotify() {
		super.addNotify();
		if (!timer.isRunning()) {
			timer.start();
		}
	}
	
	@Override
	public void removeNotify() {
		if (timer.isRunning()) {
			timer.stop();
		}
		super.removeNotify();
	}
	
	public static class PreviewPanelEvent extends EventObject {
		
		private static final long serialVersionUID = 1L;

		public PreviewPanelEvent(Object src) {
			super(src);
		}
	}
	
	private final Object lock = new Object();
	
	private long loadingTicket;
	
	private long loadedTicket;
	
	private long firstWaitingTimestamp;
	
	private boolean indicatorShown;
	
	private String title;
	
	private JLabel lblTitle;
	
	private PreviewImagePanel previewImgPanel;
	
	private LinkedList<PreviewPanelListener> listeners = new LinkedList<PreviewPanelListener>();

	
	public PreviewPanel() {
		setLayout(new BorderLayout());

		final AppConfig appConfig = AppConfig.getInstance();
		final Properties strings = LocalizedResourcePropertyLoader.getInstance().getLocalizedProperties(STRINGS_RESOURCE);
		
		lblTitle = new JLabel();
		lblTitle.setBorder(BorderFactory.createEmptyBorder(3, 10, 3, 3));
		
		indicatorText = strings.getProperty("indicatorText");
		indicatorDelay = appConfig.getPreviewIndicatorDelay();

		UIUtility uiUtl = UIUtility.getInstance();
		JButton saveBtn = uiUtl.createIconButton("icons/save.png");
		JButton copyBtn = uiUtl.createIconButton("icons/copy.png");
		JButton colorBtn = uiUtl.createIconButton("icons/color.png");
		JButton informationBtn = uiUtl.createIconButton("icons/information.png");
		JButton favoriteBtn = uiUtl.createIconButton("icons/favorite.png");
		JButton flipHolizontalBtn = uiUtl.createIconButton("icons/flip.png");

		saveBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				savePicture(new PreviewPanelEvent(PreviewPanel.this));
			}
		});
		copyBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				copyPicture(new PreviewPanelEvent(PreviewPanel.this));
			}
		});
		colorBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				changeBackgroundColor(new PreviewPanelEvent(PreviewPanel.this));
			}
		});
		informationBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				showInformation(new PreviewPanelEvent(PreviewPanel.this));
			}
		});
		favoriteBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				addFavorite(new PreviewPanelEvent(PreviewPanel.this));
			}
		});
		flipHolizontalBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				flipHolizontal(new PreviewPanelEvent(PreviewPanel.this));
			}
		});
		
		saveBtn.setToolTipText(strings.getProperty("tooltip.save"));
		copyBtn.setToolTipText(strings.getProperty("tooltip.copy"));
		colorBtn.setToolTipText(strings.getProperty("tooltip.changeBgColor"));
		informationBtn.setToolTipText(strings.getProperty("tooltip.showInformation"));
		favoriteBtn.setToolTipText(strings.getProperty("tooltip.registerFavorites"));
		flipHolizontalBtn.setToolTipText(strings.getProperty("tooltip.flipHorizontal"));

		JToolBar toolBar = new JToolBar(); 
		toolBar.setFloatable(false);
		toolBar.add(flipHolizontalBtn);
		toolBar.add(copyBtn);
		toolBar.add(saveBtn);
		toolBar.add(Box.createHorizontalStrut(8));
		toolBar.add(colorBtn);
		toolBar.add(Box.createHorizontalStrut(4));
		toolBar.add(favoriteBtn);
		toolBar.add(informationBtn);
		JPanel previewPaneHeader = new JPanel();
		previewPaneHeader.setLayout(new BorderLayout());
		previewPaneHeader.add(lblTitle, BorderLayout.WEST);
		previewPaneHeader.add(toolBar, BorderLayout.EAST);

		previewImgPanel = new PreviewImagePanel();

		JScrollPane sp2 = new JScrollPane(previewImgPanel);
		sp2.setAutoscrolls(false);
		sp2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		sp2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		
		add(previewPaneHeader, BorderLayout.NORTH);
		add(sp2, BorderLayout.CENTER);
	}
	
	public void setTitle(String title) {
		if (title == null) {
			title = "";
		}
		if (!title.equals(this.title)) {
			this.title = title;
			lblTitle.setText(title + (indicatorShown ? indicatorText : ""));
		}
	}
	
	public String getTitle() {
		return this.title;
	}
	
	protected void onTimer() {
		boolean waiting;
		long firstRequest;
		synchronized (lock) {
			waiting = (loadingTicket > loadedTicket);
			firstRequest = firstWaitingTimestamp;
		}
		boolean indicatorShown = (waiting && ((System.currentTimeMillis() - firstRequest) > indicatorDelay));
		if (this.indicatorShown != indicatorShown) {
			this.indicatorShown = indicatorShown;
			lblTitle.setText(title + (indicatorShown ? indicatorText : ""));
		}
	}

	public void setLoadingRequest(long ticket) {
		synchronized (lock) {
			if (this.loadingTicket <= this.loadedTicket) {
				this.firstWaitingTimestamp = System.currentTimeMillis();
			}
			this.loadingTicket = ticket;
		}
	}
	
	public void setLoadingComplete(long ticket) {
		synchronized (lock) {
			this.loadedTicket = ticket;
		}
	}

	public void setPreviewImage(BufferedImage previewImg) {
		previewImgPanel.setPreviewImage(previewImg);
	}

	public BufferedImage getPreviewImage() {
		return previewImgPanel.getPreviewImage();
	}
	
	public Color getImageBgColor() {
		return previewImgPanel.getImageBgColor();
	}
	
	public void setImageBgColor(Color bgColor) {
		previewImgPanel.setImageBgColor(bgColor);
	}
	
	public void addPreviewPanelListener(PreviewPanelListener listener) {
		if (listener == null) {
			throw new IllegalArgumentException();
		}
		listeners.add(listener);
	}
	
	public void removePreviewPanelListener(PreviewPanelListener listener) {
		listeners.remove(listener);
	}
	
	protected void savePicture(PreviewPanelEvent e) {
		for (PreviewPanelListener listener : listeners) {
			listener.savePicture(e);
		}
	}
	
	protected void flipHolizontal(PreviewPanelEvent e) {
		for (PreviewPanelListener listener : listeners) {
			listener.flipHorizontal(e);
		}
	}
	
	protected void copyPicture(PreviewPanelEvent e) {
		for (PreviewPanelListener listener : listeners) {
			listener.copyPicture(e);
		}
	}

	protected void changeBackgroundColor(PreviewPanelEvent e) {
		for (PreviewPanelListener listener : listeners) {
			listener.changeBackgroundColor(e);
		}
	}

	protected void showInformation(PreviewPanelEvent e) {
		for (PreviewPanelListener listener : listeners) {
			listener.showInformation(e);
		}
	}

	protected void addFavorite(PreviewPanelEvent e) {
		for (PreviewPanelListener listener : listeners) {
			listener.addFavorite(e);
		}
	}
}


class PreviewImagePanel extends JPanel {
	private static final long serialVersionUID = 1L;

	private Color bgColor;
	
	private BufferedImage previewImg;

	public PreviewImagePanel() {
		super();

		AppConfig appConfig = AppConfig.getInstance();
		bgColor = appConfig.getDefaultImageBgColor();
	}
	
	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		if (previewImg != null) {
			int client_w = getWidth();
			int client_h = getHeight();
			
			Color oldc = g.getColor();
			try {
				g.setColor(bgColor);
				g.fillRect(0, 0, client_w, client_h);
			} finally {
				g.setColor(oldc);
			}
			
			int w = previewImg.getWidth();
			int h = previewImg.getHeight();

			int offset_x = 0;
			if (w < client_w) {
				offset_x = (client_w - w) / 2;
			}
			int offset_y = 0;
			if (h < client_h) {
				offset_y = (client_h - h) / 2;
			}
			g.drawImage(previewImg, offset_x, offset_y, offset_x + w, offset_y + h, 0, 0, w, h, null);
		}
	}
	
	public void setPreviewImage(BufferedImage previewImg) {
		this.previewImg = previewImg;
		if (previewImg != null) {
			int w = previewImg.getWidth();
			int h = previewImg.getHeight();
			setPreferredSize(new Dimension(w, h));
			revalidate();
		}
		repaint();
	}

	public BufferedImage getPreviewImage() {
		return previewImg;
	}
	
	public void setImageBgColor(Color bgColor) {
		if (bgColor == null) {
			return;
		}
		if (this.bgColor != bgColor) {
			this.bgColor = bgColor;
			repaint();
		}
	}
	
	public Color getImageBgColor() {
		return this.bgColor;
	}
}


