package net.psammead.commonist.ui;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.List;

import javax.swing.*;

import net.psammead.commonist.*;
import net.psammead.commonist.data.*;
import net.psammead.commonist.util.*;
import net.psammead.util.ui.*;

/** displays a scrollable List of ImageUIs */
public class ImageListUI implements UI {
	// components
	private	JPanel	panel;
	private JPanel	listPanel;
	private	JLabel	selectStatus;

	// state
	private String	programHeading;
	private Image	programIcon;
	private List<ImageUI>	imageUIs;
	
	/** contains a List of ImageUI objects */
	public ImageListUI(String programHeading, Image programIcon) {
		this.programHeading	= programHeading;
		this.programIcon		= programIcon;
		
		imageUIs	= new ArrayList<ImageUI>();
		
		//------------------------------------------------------------------------------
		//## components

		listPanel	= new ListPanel();
		listPanel.setLayout(new BoxLayout(listPanel, BoxLayout.Y_AXIS));
		
		JScrollPane	scroll	= new JScrollPane(listPanel, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		scroll.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));	//### scrollBorder?
		
		//var	bar	= scroll.getVerticalScrollBar();

		JButton	selectAllButton		= new JButton(Messages.text("imageList.selectAll"));
		JButton	deselectAllButton	= new JButton(Messages.text("imageList.deselectAll"));
		selectStatus		= new JLabel();
		
		//------------------------------------------------------------------------------
		//## layout
		
		panel	= new GridBagPanel();
		panel.setBorder(Constants.PANEL_BORDER);

		panel.add(deselectAllButton,	"at 0/0 size 1/1 weight 0.001/0 anchor center fill horizontal insets 0/0/0/0");
		panel.add(selectAllButton,		"at 1/0 size 1/1 weight 0.001/0 anchor center fill horizontal insets 0/0/0/0");
		panel.add(selectStatus,			"at 2/0 size 1/1 weight 1/0 anchor center fill horizontal insets 0/4/0/4");
		panel.add(scroll,				"at 0/1 size 3/1 weight 1/1 anchor center fill both insets 0/0/0/0");

		//------------------------------------------------------------------------------
		//## wiring
		
		selectAllButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				updateSelectStatus(true);
			}
		});
		
		deselectAllButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				updateSelectStatus(false);
			}
		});
		
		//------------------------------------------------------------------------------
		//## init
		
		updateSelectStatus();
	}
	
	/** UI: returns the JComponent this UI controls */
	public JComponent getComponent() {
		return panel;
	}

	/** removes all ImageUI objects */
	public void clear() {
		imageUIs.clear();
		listPanel.removeAll();
	}
	
	/** adds a File UI */
	public void add(File file, Icon icon) {
		ImageUI	imageUI	= new ImageUI(file, icon, programHeading, programIcon, new ImageUI.Callback() {
			public void updateSelectStatus() { ImageListUI.this.updateSelectStatus(); }
		});
		
		imageUIs.add(imageUI);
		if (!imageUIs.isEmpty()) {
			listPanel.add(new JSeparator());
		}
		listPanel.add(imageUI.getComponent());
	}
	
	/** get the select status and update the display */
	public void updateSelectStatus() {
		int		allFiles		= 0;
		long	allBytes		= 0;
		int		selectedFiles	= 0;
		long	selectedBytes	= 0;
		
		for (Iterator<ImageUI> it=imageUIs.iterator(); it.hasNext();) {
			ImageUI	imageUI		= it.next();
			long	fileSize	= imageUI.getData().file.length();
			allFiles	++;
			allBytes	+= fileSize;
			if (imageUI.isUploadSelected()) {
				selectedFiles	++;
				selectedBytes	+= fileSize;
			}
		}
	
		selectStatus.setText(Messages.message("imageList.selected", new Object[] {
			new Integer(selectedFiles), new Integer(allFiles), TextUtil.human(selectedBytes), TextUtil.human(allBytes) 
		}));
	}
	
	public ImageListData getData() {
		List<ImageData>	out	= new ArrayList<ImageData>();
		for (Iterator<ImageUI> it=imageUIs.iterator(); it.hasNext();) {
			ImageUI	imageUI	= it.next();
			out.add(imageUI.getData());
		}
		return new ImageListData(out);
	}
	
	//------------------------------------------------------------------------------
	//## private methods
	
	/** checks or unchecks the upload checkbox in all images */
	private void updateSelectStatus(boolean all) {
		for (Iterator<ImageUI> it=imageUIs.iterator(); it.hasNext();) {
			ImageUI	imageUI	= it.next();
			imageUI.setUploadSelected(all);
		}
		updateSelectStatus();
	}
	
	//------------------------------------------------------------------------------
	//## private classes
	
	/** a Scrollable Panel scrolling to even tickets */
	private class ListPanel extends JPanel implements Scrollable {
		/**	visibleRect	The view area visible within the viewport
			orientation	SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
			direction	Less than zero to scroll up/left, greater than zero for down/right.
		*/
		public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
			if (orientation == SwingConstants.HORIZONTAL)	return 1;
			
			if (direction < 0) {
				Component	component	= listPanel.getComponentAt(visibleRect.x, visibleRect.y - 2);
				int	visible		= visibleRect.y ;
				int	target		= component != null ? component.getY() : 0;
				return visible - target;
			}
			else {
				Component	component	= listPanel.getComponentAt(visibleRect.x, visibleRect.y + visibleRect.height);
				int	visible		= visibleRect.y + visibleRect.height;
				int	target		= component != null ? (component.getY() + component.getHeight()) : listPanel.getHeight();
				return target - visible;
			}
		}
		
		/**	visibleRect	The view area visible within the viewport
			orientation	SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
			direction	Less than zero to scroll up/left, greater than zero for down/right.
		*/
		public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
			if (orientation == SwingConstants.HORIZONTAL)	return 1;
			
			if (direction < 0)	return Math.min(visibleRect.height, visibleRect.y - 0);
			else				return Math.min(visibleRect.height, listPanel.getHeight()  - (visibleRect.y + visibleRect.height));
		}  
		
		public Dimension getPreferredScrollableViewportSize()	{ return listPanel.getPreferredSize(); }
		public boolean getScrollableTracksViewportWidth()		{ return false;	}
		public boolean getScrollableTracksViewportHeight()		{ return false;	}
	}
}
