// $Id: Datatype.java,v 1.19 2005/01/04 17:56:28 amdus Exp $

import java.util.Hashtable;
import java.io.StringReader;
import java.math.BigDecimal;
import java.math.BigInteger;

import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.XMLReaderFactory;
import org.apache.xerces.impl.dv.xs.DayDV;
import org.apache.xerces.impl.dv.xs.YearDV;
import org.apache.xerces.impl.dv.xs.TimeDV;
import org.apache.xerces.impl.dv.xs.DateDV;
import org.apache.xerces.impl.dv.xs.FloatDV;
import org.apache.xerces.impl.dv.xs.MonthDV;
import org.apache.xerces.impl.dv.xs.AnyURIDV;
import org.apache.xerces.impl.dv.xs.StringDV;
import org.apache.xerces.impl.dv.xs.DoubleDV;
import org.apache.xerces.impl.dv.xs.BooleanDV;
import org.apache.xerces.impl.dv.xs.DecimalDV;
import org.apache.xerces.impl.dv.xs.DateTimeDV;
import org.apache.xerces.impl.dv.xs.DurationDV;
import org.apache.xerces.impl.dv.xs.MonthDayDV;
import org.apache.xerces.impl.dv.xs.YearMonthDV;
import org.apache.xerces.impl.dv.xs.HexBinaryDV;
import org.apache.xerces.impl.dv.xs.TypeValidator;
import org.apache.xerces.impl.dv.xs.Base64BinaryDV;

public class Datatype {

  static Hashtable num = null;
  static Hashtable anum = null;

  static final boolean isNumeric(String dt) {
    if (num == null) {
      num = new Hashtable();
      num.put(Euler.XSDbyte, new Object());
      num.put(Euler.XSDdecimal, new Object());
      num.put(Euler.XSDdouble, new Object());
      num.put(Euler.XSDfloat, new Object());
      num.put(Euler.XSDint, new Object());
      num.put(Euler.XSDinteger, new Object());
      num.put(Euler.XSDlong, new Object());
      num.put(Euler.XSDnegativeInteger, new Object());
      num.put(Euler.XSDnonNegativeInteger, new Object());
      num.put(Euler.XSDnonPositiveInteger, new Object());
      num.put(Euler.XSDpositiveInteger, new Object());
      num.put(Euler.XSDshort, new Object());
      num.put(Euler.XSDunsignedByte, new Object());
      num.put(Euler.XSDunsignedInt, new Object());
      num.put(Euler.XSDunsignedLong, new Object());
      num.put(Euler.XSDunsignedShort, new Object());
      num.put(Euler.MATHabsoluteValue, new Object());
      num.put(Euler.MATHatan2, new Object());
      num.put(Euler.MATHcos, new Object());
      num.put(Euler.MATHcosh, new Object());
      num.put(Euler.MATHdegrees, new Object());
      num.put(Euler.MATHdifference, new Object());
      num.put(Euler.MATHequalTo, new Object());
      num.put(Euler.MATHexponentiation, new Object());
      num.put(Euler.MATHgreaterThan, new Object());
      num.put(Euler.MATHintegerQuotient, new Object());
      num.put(Euler.MATHlessThan, new Object());
      num.put(Euler.MATHmemberCount, new Object());
      num.put(Euler.MATHnegation, new Object());
      num.put(Euler.MATHnotEqualTo, new Object());
      num.put(Euler.MATHnotGreaterThan, new Object());
      num.put(Euler.MATHnotLessThan, new Object());
      num.put(Euler.MATHproduct, new Object());
      num.put(Euler.MATHproofCount, new Object());
      num.put(Euler.MATHquotient, new Object());
      num.put(Euler.MATHremainder, new Object());
      num.put(Euler.MATHrounded, new Object());
      num.put(Euler.MATHsin, new Object());
      num.put(Euler.MATHsinh, new Object());
      num.put(Euler.MATHsum, new Object());
      num.put(Euler.MATHtan, new Object());
      num.put(Euler.MATHtanh, new Object());
    }
    return num.get(dt) != null;
  }

  static final boolean isAlphaNumeric(String dt) {
    if (anum == null) {
      anum = new Hashtable();
      anum.put(Euler.XSDID, new Object());
      anum.put(Euler.XSDIDREF, new Object());
      anum.put(Euler.XSDNCName, new Object());
      anum.put(Euler.XSDNMTOKEN, new Object());
      anum.put(Euler.XSDName, new Object());
      anum.put(Euler.XSDanyURI, new Object());
      anum.put(Euler.XSDlanguage, new Object());
      anum.put(Euler.XSDnormalizedString, new Object());
      anum.put(Euler.XSDstring, new Object());
      anum.put(Euler.XSDtoken, new Object());
    }
    return anum.get(dt) != null;
  }

  static final int compare(String dt1, String s1, String dt2, String s2) {
    String dt = dt1;
    if (isNumeric(dt1) && isNumeric(dt2) && dt1 != dt2) dt = Euler.XSDdouble;
    if (isAlphaNumeric(dt1) && isAlphaNumeric(dt2) && dt1 != dt2) dt = Euler.XSDstring;
    try {
      if (dt == Euler.XSDID) return s1.compareTo(s2);
      if (dt == Euler.XSDIDREF) return s1.compareTo(s2);
      if (dt == Euler.XSDNCName) return s1.compareTo(s2);
      if (dt == Euler.XSDNMTOKEN) return s1.compareTo(s2);
      if (dt == Euler.XSDName) return s1.compareTo(s2);
      if (dt == Euler.XSDanyURI) return s1.compareTo(s2);
      if (dt == Euler.XSDbase64Binary) return s1.compareTo(s2);
      if (dt == Euler.XSDboolean) return s1.compareTo(s2);
      if (dt == Euler.XSDbyte) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDdate) {TypeValidator dv = new DateDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDdateTime) {TypeValidator dv = new DateTimeDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDdecimal) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDdouble) {TypeValidator dv = new DoubleDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDduration) {TypeValidator dv = new DurationDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDfloat) {TypeValidator dv = new FloatDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDgDay) {TypeValidator dv = new DayDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDgMonth) {TypeValidator dv = new MonthDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDgMonthDay) {TypeValidator dv = new MonthDayDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDgYear) {TypeValidator dv = new YearDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDgYearMonth) {TypeValidator dv = new YearMonthDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDhexBinary) return s1.compareTo(s2);
      if (dt == Euler.XSDint) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDinteger) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDlanguage) return s1.compareTo(s2);
      if (dt == Euler.XSDlong) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDnegativeInteger) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDnonNegativeInteger) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDnonPositiveInteger) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDnormalizedString) return s1.compareTo(s2);
      if (dt == Euler.XSDpositiveInteger) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDshort) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDstring) return s1.compareTo(s2);
      if (dt == Euler.XSDtime) {TypeValidator dv = new TimeDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDtoken) return s1.compareTo(s2);
      if (dt == Euler.XSDunsignedByte) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDunsignedInt) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDunsignedLong) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      if (dt == Euler.XSDunsignedShort) {TypeValidator dv = new DecimalDV(); return dv.compare(dv.getActualValue(s1.trim(), null), dv.getActualValue(s2.trim(), null));}
      return s1.compareTo(s2);
    }
    catch (Exception e) {
      Outputter.getInstance().log("DataType", "compare", "** " + e, ILogger.FINE);
      return s1.compareTo(s2);
    }
  }

  static final boolean clash(String dt, String s) {
    if (s.startsWith("\"\"\"")) return false;
    s = s.substring(1, s.length() - 1);
    try {
      if (dt == Euler.RDFXMLLiteral) {
        XMLReader xr = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
        InputSource is = new InputSource(new StringReader(s));
        xr.parse(is);
        return false;
      }
      if (dt == Euler.XSDID) return new StringDV().getActualValue(s, null) == null;
      if (dt == Euler.XSDIDREF) return new StringDV().getActualValue(s, null) == null;
      if (dt == Euler.XSDNCName) return new StringDV().getActualValue(s, null) == null;
      if (dt == Euler.XSDNMTOKEN) return new StringDV().getActualValue(s, null) == null;
      if (dt == Euler.XSDName) return new StringDV().getActualValue(s, null) == null;
      if (dt == Euler.XSDanyURI) return new AnyURIDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDbase64Binary) return new Base64BinaryDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDboolean) return new BooleanDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDbyte) return new Byte(s) == null;
      if (dt == Euler.XSDdate) return new DateDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDdateTime) return new DateTimeDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDdecimal) return new BigDecimal(s) == null;
      if (dt == Euler.XSDdouble) return new DoubleDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDduration) return new DurationDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDfloat) return new FloatDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDgDay) return new DayDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDgMonth) return new MonthDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDgMonthDay) return new MonthDayDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDgYear) return new YearDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDgYearMonth) return new YearMonthDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDhexBinary) return new HexBinaryDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDint) return new Integer(s) == null;
      if (dt == Euler.XSDinteger) return new BigInteger(s) == null;
      if (dt == Euler.XSDlanguage) return new StringDV().getActualValue(s, null) == null;
      if (dt == Euler.XSDlong) return new Long(s) == null;
      if (dt == Euler.XSDnegativeInteger) return new BigInteger(s) == null || new BigInteger(s).compareTo(new BigInteger("0")) >= 0;
      if (dt == Euler.XSDnonNegativeInteger) return new BigInteger(s) == null || new BigInteger(s).compareTo(new BigInteger("0")) < 0;
      if (dt == Euler.XSDnonPositiveInteger) return new BigInteger(s) == null || new BigInteger(s).compareTo(new BigInteger("0")) > 0;
      if (dt == Euler.XSDnormalizedString) return new StringDV().getActualValue(s, null) == null;
      if (dt == Euler.XSDpositiveInteger) return new BigInteger(s) == null || new BigInteger(s).compareTo(new BigInteger("0")) <= 0;
      if (dt == Euler.XSDshort) return new Short(s) == null;
      if (dt == Euler.XSDstring) return new StringDV().getActualValue(s, null) == null;
      if (dt == Euler.XSDtime) return new TimeDV().getActualValue(s.trim(), null) == null;
      if (dt == Euler.XSDtoken) return new StringDV().getActualValue(s, null) == null;
      if (dt == Euler.XSDunsignedByte) return new Short(s) == null || Short.parseShort(s) < 0 || Short.parseShort(s) > 255;
      if (dt == Euler.XSDunsignedInt) return new Long(s) == null || Long.parseLong(s) < 0 || Long.parseLong(s) > 4294967295L;
      if (dt == Euler.XSDunsignedLong) return new BigInteger(s) == null || new BigInteger(s).compareTo(new BigInteger("0")) < 0 || new BigInteger(s).compareTo(new BigInteger("18446744073709551615")) > 0;
      if (dt == Euler.XSDunsignedShort) return new Integer(s) == null || Integer.parseInt(s) < 0 || Integer.parseInt(s) > 65535;
      return true;
    }
    catch (Exception e) {
      Outputter.getInstance().log("DataType", "clash", "** " + s + ": " + e, ILogger.FINE);
      return true;
    }
  }
}
