package junkutil.set;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import junkutil.common.StringUtil;

/**
 * Listを集合論的に扱う。
 * @author Hiroyuki Shiota
 */
public class LzList {
	private java.util.List base;

	/**
	 * コンストラクタ
	 */
	public LzList() {
		base = new ArrayList();
	}
	/**
	 * コンストラクタ
	 * @param list
	 */
	public LzList(List list) {
		base = list;
	}
	/**
	 * コンストラクタ
	 * @param list
	 */
	public LzList(Object[] args) {
		base = Arrays.asList(args);
	}
	/**
	 * コンストラクタ
	 * @param list
	 */
	public LzList(Set set) {
		base = Arrays.asList(set.toArray());
	}

	/**
	 * リストを取得する。
	 * @return
	 */
	public List list() {
		return base;
	}
	
	/**
	 * orを取得する。
	 * @param arg
	 * @return
	 */
	public LzList or(List arg) {
		List list = new ArrayList(base);
		for (int i = 0; i < arg.size(); i++) {
			if (!base.contains(arg.get(i))) list.add(arg.get(i));
		}
		return new LzList(list);
	}
	
	/**
	 * andを取得する。
	 * @param arg
	 * @return
	 */
	public LzList and(List arg) {
		List list = new ArrayList();
		for (int i = 0; i < arg.size(); i++) {
			if (base.contains(arg.get(i))) list.add(arg.get(i));
		}
		return new LzList(list);
	}
	
	private Comparator compStrAsc = new Comparator() {
		public int compare(Object o1, Object o2) {
			return o1.toString().compareTo(o2.toString());
		}
	};
	private Comparator compStrDesc = new Comparator() {
		public int compare(Object o1, Object o2) {
			return -(o1.toString().compareTo(o2.toString()));
		}
	};
	
	/**
	 * 昇順でソートする。
	 * @return
	 */
	public LzList sortAsc() {
		return sort(compStrAsc);
	}
	
	/**
	 * 降順でソートする。
	 * @return
	 */
	public LzList sortDesc() {
		return sort(compStrDesc);
	}
	
	/**
	 * 指定順でソートする。
	 * @return
	 */
	public LzList sort(Comparator c) {
		List list = new ArrayList(base);
		Collections.sort(list, c);
		return new LzList(list);
	}
	
	/**
	 * 絞り込みを行う。nullは除外される。
	 * @param re
	 * @return
	 */
	public LzList grep(String re) {
		List list = new ArrayList();
		Pattern pattern = Pattern.compile(re);
		for (int i = 0; i < base.size(); i++) {
			Object obj = base.get(i);
			if (obj == null) continue;
			if (StringUtil.match(obj.toString(), pattern)) {
				list.add(obj);
			}
		}
		return new LzList(list);
	}
	
	/**
	 * 逆絞り込みを行う。nullは除外される。
	 * @param re
	 * @return
	 */
	public LzList ungrep(String re) {
		List list = new ArrayList();
		Pattern pattern = Pattern.compile(re);
		for (int i = 0; i < base.size(); i++) {
			Object obj = base.get(i);
			if (obj == null) continue;
			if (!StringUtil.match(obj.toString(), pattern)) {
				list.add(obj);
			}
		}
		return new LzList(list);
	}
	
	/**
	 * リストを結合する。
	 * @param arg
	 * @return
	 */
	public LzList join(List arg) {
		List list = new ArrayList(base);
		for (Iterator i = arg.iterator(); i.hasNext();) {
			list.add(i.next());
		}
		return new LzList(list);
	}
	
	/**
	 * ユニークなリストを取得する。
	 * @param arg
	 * @return
	 */
	public LzList uniq() {
		Map map = new HashMap();
		for (int i = 0; i < base.size(); i++) {
			map.put(base.get(i), Object.class);
		}
		return new LzList(new ArrayList(map.keySet()));
	}
	
	/**
	 * 等しいかどうかをテストする
	 * @param arg
	 * @return
	 */
	public boolean equals(List arg) {
		if (base.size() != arg.size()) return false;
		for (int i = 0; i < base.size(); i++) {
			Object obj1 = base.get(i);
			Object obj2 = arg.get(i);
			if (!obj1.equals(obj2)) return false;
		}
		return true;
	}

	/**
	 * 順序を揃えたあと、等しいかどうかをテストする
	 * @param arg
	 * @return
	 */
	public boolean equalsOnSort(List arg) {
		if (base.size() != arg.size()) return false;
		LzList sortedBase = new LzList(base).sortAsc();
		List sortedArg = new LzList(arg).sortAsc().list();
		return equals(arg);
	}
	
	/**
	 * 等しいかどうかをテストする
	 * @param arg
	 * @return
	 */
	public boolean equals(String arg) {
		return toString().equals(arg);
	}
	
	/**
	 * @Override
	 */
	public String toString() {
		return base.toString();
	}
}
