package charactermanaj.ui.model;

import java.awt.Color;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import charactermanaj.model.PartsCategory;
import charactermanaj.model.PartsColorInfo;
import charactermanaj.model.PartsColorManager;
import charactermanaj.model.PartsIdentifier;
import charactermanaj.model.PartsSet;
import charactermanaj.ui.ImageSelectPanel;

public class PartsSelectionManager {

	private HashMap<PartsCategory, ImageSelectPanel> imageSelectPanels = new HashMap<PartsCategory, ImageSelectPanel>();
	
	private PartsColorManager partsColorMrg;
	
	/**
	 * 背景色
	 */
	private Color imageBgColor = Color.white;
	
	/**
	 * アフィン変換用のパラメータ.<br>
	 * 変換しない場合はnull.<br>
	 */
	private double[] affineTransformParameter;
	
	/**
	 * パーツをロードする.
	 */
	public void loadParts() {
		for (ImageSelectPanel panel : imageSelectPanels.values()) {
			panel.loadParts();
		}
	}
	
	public PartsSelectionManager(PartsColorManager partsColorMrg) {
		if (partsColorMrg == null) {
			throw new IllegalArgumentException();
		}
		this.partsColorMrg = partsColorMrg;
	}
	
	public void register(ImageSelectPanel imageSelectPanel) {
		if (imageSelectPanel == null) {
			throw new IllegalArgumentException();
		}
		imageSelectPanels.put(imageSelectPanel.getPartsCategory(), imageSelectPanel);
	}

	public List<PartsIdentifier> getSelectedPartsIdentifiers(PartsCategory partsCategory) {
		if (partsCategory == null) {
			throw new IllegalArgumentException();
		}
		ImageSelectPanel panel = imageSelectPanels.get(partsCategory);
		if (panel != null) {
			return Collections.unmodifiableList(panel.getSelectedPartsIdentifiers());
		}
		return Collections.emptyList();
	}

	public PartsIdentifier getSelectedPartsIdentifier(PartsCategory partsCategory) {
		if (partsCategory == null) {
			throw new IllegalArgumentException();
		}
		ImageSelectPanel panel = imageSelectPanels.get(partsCategory);
		if (panel != null) {
			return panel.getSelectedPartsIdentifier();
		}
		return null;
	}
	
	public Collection<PartsCategory> getAllCategories() {
		ArrayList<PartsCategory> partsCategories = new ArrayList<PartsCategory>();
		partsCategories.addAll(imageSelectPanels.keySet());
		return partsCategories;
	}
	
	/**
	 * 各カテゴリの選択状態と背景をパーツセットで指定されたものに設定します.<br>
	 * @param partsSet パーツセット
	 */
	public void selectPartsSet(PartsSet partsSet) {
		if (partsSet == null) {
			throw new IllegalArgumentException();
		}

		for (ImageSelectPanel panel : imageSelectPanels.values()) {
			PartsCategory partsCategory = panel.getPartsCategory();
			List<PartsIdentifier> partsIdentifiers = partsSet.get(partsCategory);
			panel.selectParts(partsIdentifiers);
			if (partsIdentifiers != null) {
				for (PartsIdentifier partsIdentifier : partsIdentifiers) {
					PartsColorInfo partsColorInfo = partsSet.getColorInfo(partsIdentifier);
					if (partsColorInfo != null) {
						partsColorMrg.setPartsColorInfo(partsIdentifier, partsColorInfo, false);
					}
				}
			}
		}

		Color bgColor = partsSet.getBgColor();
		if (bgColor != null) {
			imageBgColor = bgColor; 
		}
		
		affineTransformParameter = partsSet.getAffineTransformParameter(); // clone済み
	}
	
	/**
	 * 現在の選択中のパーツと色設定からパーツセットを構築します.
	 * 選択がなにもない場合は空のパーツセットとなります.<br>
	 * @return パーツセット
	 */
	public PartsSet createPartsSet() {
		PartsSet presetParts = new PartsSet();
		for (ImageSelectPanel imageSelectPanel : imageSelectPanels.values()) {
			PartsCategory category = imageSelectPanel.getPartsCategory();
			for (PartsIdentifier partsIdentifier : imageSelectPanel.getSelectedPartsIdentifiers()) {
				PartsColorInfo partsColorInfo = partsColorMrg.getPartsColorInfo(partsIdentifier, false);
				presetParts.appendParts(category, partsIdentifier, partsColorInfo);
			}
		}
		presetParts.setBgColor(imageBgColor);
		presetParts.setAffineTransformParameter(affineTransformParameter); // 相手側でcloneする
		return presetParts;
	}

	/**
	 * すべてのカテゴリのリストで選択中のアイテムが見えるようにスクロールする.
	 */
	public void scrollToSelectedParts() {
		for (ImageSelectPanel imageSelectPanel : imageSelectPanels.values()) {
			imageSelectPanel.scrollToSelectedRow();
		}
	}
	
	/**
	 * 指定したパーツ識別子にフォーカスを当てて、必要に応じてスクロールします.<br>
	 * 該当するパーツ識別子がどこにもなければ何もしません.<br>
	 * @param partsIdentifier パーツ識別子
	 */
	public void setSelection(PartsIdentifier partsIdentifier) {
		if (partsIdentifier == null) {
			return;
		}
		PartsCategory partsCategory = partsIdentifier.getPartsCategory();
		ImageSelectPanel imageSelectPanel = imageSelectPanels.get(partsCategory);
		if (imageSelectPanel != null) {
			imageSelectPanel.setSelection(partsIdentifier);
		}
	}
	
	/**
	 * 背景色を取得する.
	 * @return 背景色
	 */
	public Color getImageBgColor() {
		return imageBgColor;
	}

	/**
	 * 背景色を設定する
	 * @param imageBgColor 背景色
	 */
	public void setImageBgColor(Color imageBgColor) {
		if (imageBgColor == null) {
			imageBgColor = Color.white;
		}
		this.imageBgColor = imageBgColor;
	}

	/**
	 * アフィン変換用のパラメータを取得する.<br>
	 * 変換しない場合はnull.<br>
	 * @return アフィン変換用のパラメータ、もしくはnull
	 */
	public double[] getAffineTransformParameter() {
		return affineTransformParameter == null ? null : affineTransformParameter.clone();
	}
	
	/**
	 * アフィン変換用のパラメータを設定する.<br>
	 * 変換しない場合はnull.<br>
	 * 要素数は4または6でなければならない.<br>
	 * @param affineTransformParameter アフィン変換用のパラメータ、もしくはnull
	 */
	public void setAffineTransformParameter(double[] affineTransformParameter) {
		if (affineTransformParameter != null && !(affineTransformParameter.length == 4 || affineTransformParameter.length == 6)) {
			throw new IllegalArgumentException("affineTransformParameter invalid length.");
		}
		this.affineTransformParameter = affineTransformParameter == null ? null : affineTransformParameter.clone();
	}
}
