package jp.ac.takushoku_u.cs;

/**
* Sequenceクラスは系列化された順序を保持するクラスです。
* 系列順として保持されている番号は隣接マトリクスにした際の行または列番号です。
* @version 1.01
* @author 笠島 裕史(Kasajima Hiroshi)
*/
/*
* 最終更新日 2004年12月06日
*/
public class Sequence{
	
/**
* 系列順を保持する配列
*/
	private int[] queue;
	
/**
* 系列された要素に付けられている名前を保持する配列
*/
	private String[] queueName;
	
/**
* 要素数0のSequenceを生成します。
* 名前は配列番号で設定されます。
*/
	public Sequence(){
		setLength(0);
		setItemNameNumber();
	}
	
/**
* 要素数volumeのSequenceを生成します。
* 名前は配列番号で設定されます。
* @param volume 要素数
* @exception NegativeSequenceSizeException 負のサイズのSequenceを生成しようとした場合
*/
	public Sequence(int volume){
		setLength(volume);
		setItemNameNumber();
	}
	
/**
* 指定した配列を要素として持つSequenceを生成します。
* 名前は配列番号で設定されます。
* @param baseArray 要素にする配列
* @exception NegativeValueException 配列内に負の要素が指定されている場合
* @exception IllegalRelationValuesException 同じ要素番号が2つ以上あった場合
* @exception NullPointerException  baseArray が null の場合
*/
	public Sequence(int[] baseArray){
		if(isNotPositive(baseArray)){
			if(isNotSameItem(baseArray)){
				setLength(baseArray.length);
				System.arraycopy(baseArray, 0, queue, 0, baseArray.length);
				setItemNameNumber();
			}
			else{
				throw new IllegalRelationValuesException();
			}
		}
		else{
			throw new NegativeValueException();
		}
	}
	
/**
* 指定した配列を要素および要素名として持つSequenceを生成します。
* @param baseArray 要素にする配列
* @param baseNameArray 要素名にする配列
* @exception DisagreementArraySizeException 要素にする配列と要素名にする配列のサイズが一致しない場合
* @exception NegativeValueException 配列内に負の要素が指定されている場合
* @exception IllegalRelationValuesException 同じ要素番号が2つ以上あった場合
* @exception NullPointerException  baseArray または baseNameArray が null の場合
*/
	public Sequence(int[] baseArray, String[] baseNameArray){
		if(baseArray.length == baseNameArray.length){
			if(isNotPositive(baseArray)){
				if(isNotSameItem(baseArray)){
					setLength(baseArray.length);
					System.arraycopy(baseArray, 0, queue, 0, baseArray.length);
					System.arraycopy(baseNameArray, 0, queueName, 0, baseNameArray.length);
				}
				else{
					throw new IllegalRelationValuesException();
				}
			}
			else{
				throw new NegativeValueException();
			}
		}
		else{
			throw new DisagreementArraySizeException();
		}
	}
	
	
/**
* 指定された番号の要素を返します。
* @param index 指定する番号
* @return 要素
* @exception NotItemException 指定した項目が存在しない場合
*/
	public int getItem(int index){
		if(isSequenceEntityPoint(index)){
			return queue[index];
		}
		else{
			throw new NotItemException("index(" + index + ")");
		}
	}
	
/**
* 指定した番号に要素を設定します。
* @param index 指定する番号(Sequqnceの順番)
* @param number 指定する要素
* @exception NotItemException 指定した項目が存在しない場合
*/
	public void setItem(int index, int number){
		if(isSequenceEntityPoint(index)){
			queue[index] = number;
		}
		else{
			throw new NotItemException("index(" + index + ")");
		}
	}
	
/**
* 指定された番号の要素名を返します。
* @param index 指定する番号
* @return 要素名
* @exception NotItemException 指定した項目が存在しない場合
*/
	public String getItemName(int index){
		if(isSequenceEntityPoint(index)){
			return queueName[index];
		}
		else{
			throw new NotItemException("index(" + index + ")");
		}
	}
	
/**
* 指定した番号に要素名を設定します。
* @param index 指定する番号(Sequqnceの順番)
* @param name 指定する要素名
* @exception NotItemException 指定した項目が存在しない場合
*/
	public void setItemName(int index, String name){
		if(isSequenceEntityPoint(index)){
			queueName[index] = name;
		}
		else{
			throw new NotItemException("index(" + index + ")");
		}
	}
	
/**
* 指定した要素の番号(順番)を返します。
* @param element 指定した要素
* @return 番号
* @exception NotItemException 指定した項目が存在しない場合
*/
	public int getNumber(int element){
		for(int i = 0; i < getLength(); i++){
			if(getItem(i) == element){
				return i;
			}
		}
	
		throw new NotItemException("element(" + element + ")");
	}
	
/**
* 指定した要素名の番号(順番)を返します。
* @param element 指定した要素名
* @return 番号
* @exception NotItemException 指定した項目が存在しない場合
*/
	public int getNumberName(String element){
		for(int i= 0; i < getLength(); i++){
			if(getItemName(i).equals(element)){
				return i;
			}
		}
	
		throw new NotItemException("element(" + element + ")");
	}
	
/**
* Sequenceに他のSequenceをコピーします。
* @param copySequence コピー元のSequence
*/
	public void sequenceCopy(Sequence copySequence){
		if(copySequence.getLength() != getLength()){
			setLength(copySequence.getLength());
		}
		for(int i = 0; i < copySequence.getLength(); i++){
			setItem(i , copySequence.getItem(i));
			setItemName(i , copySequence.getItemName(i));
		}
	}
	
/**
* 名前を入れる配列に配列番号を設定します。<BR>
* 配列番号は0から始まるため、0から順に設定されます。 
*/
	public void setItemNameNumber(){
		for (int i = 0; i < getLength(); i++){
			setItemName(i, i +"");
		}
	}
	
/**
* 名前を入れる配列にstartから始まる番号を設定します。<BR>
* @param start 最初の名前を付ける番号
*/
	public void setItemNameNumber(int start){
		for (int i = 0; i < getLength(); i++){
			setItemName(i, i + start +"");
		}
	}
	
/**
* Sequenceのサイズを返します。
* @return サイズ
*/
	public int getLength(){
		return queue.length;
	}
	
/**
* Sequenceのサイズを設定します。
* @param volume 指定するサイズ
* @exception NegativeSequenceSizeException 負のサイズのSequenceを生成しようとした場合
*/
	private void setLength(int volume){
		if(volume >= 0){
			queue = new int[volume];
			queueName = new String[volume];
		}
		else{
			throw new NegativeSequenceSizeException();
		}
	}
	
/**
* 指定された要素が存在するかチェックします。
* @param index 指定する要素
* @return 存在すれば true
*/
	public boolean isSequenceEntityPoint(int index){
		return (0 <= index) && (index < getLength());
	}
	
/**
* 要素として指定した要素に負の数がないかチェックします。
* @param チェックする配列
* @return 負の要素がなければ true
* @exception NullPointerException  array が null の場合
*/
	private boolean isNotPositive(int[] array){
		boolean flag = true;
		for(int i= 0; i < array.length; i++){
			if(array[i] < 0){
				flag = false;
			}
		}
		return flag;
	}
/**
* 要素として指定した要素に同じ番号がないかチェックします。
* @param チェックする配列
* @return 同じ要素がなければ true
* @exception NullPointerException  array が null の場合
*/
	private boolean isNotSameItem(int[] array){
		boolean flag = true;
		for(int i = 0; i < array.length; i++){
			for(int j = 0; j < array.length; j++){
				if(i != j && array[i] == array[j]){
					flag = false;
				}
			}
		}
		return flag;
	}
}