/*
 * Copyright 2009-2010 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.lisp.exlib;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import net.morilib.lisp.Datum2;
import net.morilib.range.CharSets;
import net.morilib.range.Interval;
import net.morilib.range.IntervalsInt;
import net.morilib.range.Range;
import net.morilib.range.RangeAdder;
import net.morilib.util.MutableTuple2;

/**
 *
 *
 * @author MORIGUCHI, Yuichiro 2011/04/09
 */
public class LispCharSet extends Datum2 {

	//
	private static final Map<String, LispCharSet> _RANGES;

	/**
	 * 
	 */
	public static final LispCharSet UNIVERSAL =
		new LispCharSet(CharSets.ALL_CHAR);

	/**
	 * 
	 */
	public static final LispCharSet GRAPHIC;

	/**
	 * 
	 */
	public static final LispCharSet WHITESPACE;

	//
	static {
		InputStream ins = LispCharSet.class.getResourceAsStream(
				"/net/morilib/lisp/exlib/charset2.txt");

		_RANGES = new HashMap<String, LispCharSet>();
		try {
			final MutableTuple2<String, RangeAdder> mt;

			mt = new MutableTuple2<String, RangeAdder>();
			CharSetPropertyParser.parse(ins,
					new CharSetPropertyHandler() {

				public void singleChar(int ch) {
					mt.getB().addInterval(getintv(ch, ch));
				}
				
				public void rangedChar(int cb, int ce) {
					mt.getB().addInterval(getintv(cb, ce));
				}
				
				public void charsetName(String name) {
					if(mt.getA() != null) {
						_RANGES.put(mt.getA(),
								new LispCharSet(mt.getB().toRange()));
					}
					mt.setA(name);
					mt.setB(new RangeAdder());
				}
			});

			GRAPHIC    = _RANGES.get("char-set:graphic");
			WHITESPACE = _RANGES.get("char-set:whitespace");
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	//
	private Range charset;

	/**
	 * 
	 * @param cs
	 */
	public LispCharSet(char... cs) {
		charset = Range.O;

		for(char c : cs) {
			charset = charset.join(
					IntervalsInt.newRightOpenInterval(c, (int)c + 1));
		}
	}

	/**
	 * 
	 * @param cs
	 */
	public LispCharSet(CharSequence cs) {
		charset = Range.O;

		for(int i = 0; i < cs.length(); i++) {
			int c = cs.charAt(i);

			charset = charset.join(
					IntervalsInt.newRightOpenInterval(c, (int)c + 1));
		}
	}

	/**
	 * 
	 * @param charset
	 */
	public LispCharSet(Range charset) {
		this.charset = charset;
	}

	//
	private static Interval getintv(int ch, int ch2) {
		return IntervalsInt.newRightOpenInterval(ch, ch2 + 1);
	}

	/**
	 * 
	 * @param s
	 * @return
	 */
	public static LispCharSet parse(CharSequence s) {
		Range r = CharSets.parse(s);

		return (r != null) ? new LispCharSet(r) : null;
	}

	/**
	 * 
	 * @param c
	 * @return
	 */
	public boolean contains(char c) {
		return charset.contains((int)c);
	}

	/**
	 * 
	 * @return
	 */
	public LispCharSet complement() {
		return new LispCharSet(charset.complement(CharSets.ALL_CHAR));
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.Datum2#toDisplayString(java.lang.StringBuilder)
	 */
	@Override
	public void toDisplayString(StringBuilder buf) {
		buf.append("#<char-set>");
	}

}
