/*
 * Copyright 2009 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;

import java.math.BigInteger;

import net.morilib.lisp.sos.LispType;
import net.morilib.util.Inclementor;
import net.morilib.util.InclementorBoundsException;

/**
 * 
 *
 *
 * @author MORIGUCHI, Yuichiro 2009
 */
public final class LispCharacter extends Atom
implements Comparable<LispCharacter>,
Inclementor<LispCharacter>, JavaObjective {

	/**
	 * 
	 */
	public static final LispCharacter NEWLINE =
		new LispCharacter('\n');

	/**
	 * 
	 */
	public static final LispCharacter SPACE = new LispCharacter(' ');

	//
	private char character;

	/**
	 * 
	 * @param ch
	 */
	public LispCharacter(char ch) {
		character = ch;
	}

	//
	private static String getName(char ch) {
		if(ch == '\n') {
			return "newline";
		} else if(ch == ' ') {
			return "space";
		} else {
			return Character.toString(ch);
		}
	}

	/**
	 * 
	 * @param name
	 * @return
	 */
	public static LispCharacter getByName(String name) {
		if("newline".equals(name)) {
			return NEWLINE;
		} else if("space".equals(name)) {
			return SPACE;
		} else {
			return null;
		}
	}

	/**
	 * @param charAt
	 * @return
	 */
	public static LispCharacter valueOf(char ch) {
		return new LispCharacter(ch);
	}

	/**
	 * @return the character
	 */
	public char getCharacter() {
		return character;
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.lisp.Atom#getResult()
	 */
	@Override
	public String getResult() {
		return "#\\" + getName(character);
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.lisp.Atom#print()
	 */
	@Override
	public String print() {
		return Character.toString(character);
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.lisp.Atom#toLispString()
	 */
	@Override
	public LispString toLispString() {
		return new LispString("#\\" + getName(character));
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.lisp.Datum#isTypeCharacter()
	 */
	public boolean isTypeCharacter() {
		return true;
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	public int compareTo(LispCharacter o) {
		return (character < o.character) ? -1 :
			((character > o.character) ? 1 : 0);
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.util.Inclementor#equalIncliment(net.morilib.util.Inclementor)
	 */
	public boolean equalIncliment(Inclementor<?> i) {
		if(i instanceof LispCharacter) {
			return character == ((LispCharacter)i).character;
		} else {
			return character == i.toInt();
		}
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.util.Inclementor#equalInt(int)
	 */
	public boolean equalInt(int i) {
		return character == i;
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.util.Inclementor#getObject()
	 */
	public LispCharacter getObject() {
		return this;
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.util.Inclementor#isZero()
	 */
	public boolean isZero() {
		return character == 0;
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.util.Inclementor#suc()
	 */
	public Inclementor<LispCharacter> suc() {
		if(character >= Character.MAX_VALUE) {
			throw new InclementorBoundsException();
		}
		return new LispCharacter((char)(character + 1));
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.util.Inclementor#suc(int)
	 */
	public Inclementor<LispCharacter> suc(int step) {
		if((character + step) >= Character.MAX_VALUE) {
			throw new InclementorBoundsException();
		}
		return new LispCharacter((char)(character + 1));
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.util.Inclementor#toInt()
	 */
	public int toInt() {
		return character;
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.util.Inclementor#hasNext()
	 */
	public boolean hasNext() {
		return character < Character.MAX_VALUE;
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.util.Inclementor#getZero()
	 */
	public Inclementor<LispCharacter> getZero() {
		return new LispCharacter((char)0);
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.util.Inclementor#equalInt(java.math.BigInteger)
	 */
	public boolean equalInt(BigInteger i) {
		return i.equals(BigInteger.valueOf(character));
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.lisp.Datum#getType()
	 */
	public LispType getType() {
		return LispType.CHAR;
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.Atom#toObject()
	 */
	public Object toObject() {
		return new Character(character);
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	public boolean equals(Object d) {
		if(d instanceof LispCharacter) {
			return character == ((LispCharacter)d).character;
		}
		return false;
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	public int hashCode() {
		int l = 17;

		l = 37 * l + (int)character;
		return l;
	}

	/*
	 * (non-Javadoc)
	 * @see net.morilib.lisp.Datum#toString()
	 */
	public String toString() {
		return Character.toString(character);
	}

}
