//
// CIMDateTime.java
//
// The contents of this file are subject to the SNIA Public License Version 1.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.snia.org/resources/openSource.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 
// License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is CIMDataType.java
// 
// The Initial Developer of the Original Code is David Simons.
//
// Contributor(s): Dan Dahl
//		   Andrei Viktorov ProdEx Technologies
//
//
// This source uses the Solaris WBEM APIs version 2.2. 
// Synchronization will be maintained with the Solaris WBEM APIS,
// which are being standardized through the Java Community Process.
//
//
// $Id: CIMDateTime.java,v 1.1 2003/07/17 18:32:55 kumpf Exp $
//
// $Log: CIMDateTime.java,v $
// Revision 1.1  2003/07/17 18:32:55  kumpf
// HP-BAPU: PEP-64 CIM Client and CIM Listener Java Interface
//
// Revision 1.1.1.1  2001/10/31 18:14:18  karl
// import of SNIA 0_7
//
// Revision 1.7  2001/07/01 11:11:49  davidsi
// - The UTCoffset was not being calculated properly in many cases
//   (from Robert St Jacques).
//
// Revision 1.2  2001/06/28 15:11:39  rstjacqu
// fixed errors with time zones and DST offsets.
//
// Revision 1.1.1.1  2001/04/17 14:33:39  rstjacqu
// no message
//
// Revision 1.6  2001/03/20 13:10:52  davidsi
// - Changed instantiation exceptions to illegal argument.
// - Fixed hours being inserted into string twice.
//
// Revision 1.5  2001/03/19 17:32:49  davidsi
// - Fixed problems whereby the timezone on the running machine could
//   affect the results comming back from a CIMDateTime instance.
//
// Revision 1.4  2001/01/16 19:24:54  davidsi
// - For Andrei Viktorov. Further fixes to time handling.
//
// Revision 1.3  2001/01/07 16:43:45  davidsi
// - Added kludge for handing '*' in date/time strings.
//
// Revision 1.2  2001/01/02 19:29:13  davidsi
// - Fixed parsing of date/time strings.
//
// Revision 1.1  2000/11/06 17:49:52  davidsi
// - Initial version.
//
//
//
//
package org.snia.wbem.cim;

import java.util.Date;
import java.io.Serializable;
import java.util.GregorianCalendar;
import java.util.Calendar;
import java.util.TimeZone;

/**
    Creates and instantiates a Java object that represents the date and time.
 */

public class CIMDateTime extends Object implements Serializable {
	/**
	 * Used to adjust the UTC offset.
	 */
	private static final int UTC_MULTIPLIER = 60000;
	
	/**
	 * All dates are converted to Greenwich Mean Time to maintain an absolute 
	 * time standard.
	 */
	private static final String GREENWICH_MEAN_TIME = "GMT";

    int UTCoffset=0;
    boolean intervalSet=false;	
	//the calendar should be set to greenwich mean time
    Calendar cal=Calendar.getInstance( 
		TimeZone.getTimeZone( GREENWICH_MEAN_TIME ));
    /*
     * realCal factors the time zone into its values so that the offset
     * is reset to 0.
     */
    Calendar realCal = null;
    int days=0;
    int hours;	int mins;
    int secs;
    int milliseconds;


   /**
    * Constructor
    */
    public CIMDateTime() {
    }	

   /**
    * Builds a CIMDateTime from an existing date
    * 
    * @param inDate The date to initialize the CIMDateType from
    */
    public CIMDateTime(Date inDate) {
	cal.setTime(inDate);
	realCal = (Calendar)cal.clone();
	UTCoffset= ( cal.get(Calendar.ZONE_OFFSET) / UTC_MULTIPLIER );
    }

    /**
     * Builds a CIMDateTime from an existing Calendar instance
     * 
     * @param inCal The caldendar to build from
     */
    public CIMDateTime(Calendar inCal) {
	cal.set(Calendar.YEAR,cal.get(Calendar.YEAR));
	cal.set(Calendar.MONTH,cal.get(Calendar.MONTH));
	cal.set(Calendar.DAY_OF_MONTH,cal.get(Calendar.DAY_OF_MONTH));
	cal.set(Calendar.HOUR,cal.get(Calendar.HOUR));
	cal.set(Calendar.MINUTE,cal.get(Calendar.MINUTE));
	cal.set(Calendar.SECOND,cal.get(Calendar.SECOND));
	cal.set(Calendar.MILLISECOND,cal.get(Calendar.MILLISECOND));
	cal.set(Calendar.ZONE_OFFSET,cal.get(Calendar.ZONE_OFFSET));
	UTCoffset= ( cal.get(Calendar.ZONE_OFFSET) / UTC_MULTIPLIER );
	realCal = (Calendar)cal.clone();
    }

   /**
    * Builds a CIMDateTime from a String that is compliant with the
    * CIM specification for absolute or interval date/times
    * 
    * @param inStr The date/time as defined by the CIM specification
    * 
    */
    public CIMDateTime(String inStr) {

	//
	// TODO - this is a temporary workaround until it can
 	// be determined exactly what a '*' should do
	//
	inStr = inStr.replace('*','0');

	if (inStr.length()!=25) {
	    // Pam Wright, Imation Change InstantiationError to
	    // IllegalArgumentException InstantiationError did not
	    // get handled properly because it is not an exception
	    // IllegalArgument is a more appropriate class to
	    // characterize the problem.
	    throw new IllegalArgumentException(inStr+" is not a valid CIM date (bad length)");
	}
	//
    	// Expect date to be in the format:
	// yyyymmddhhmmss.mmmmmmsutc
    	// if it represents an absolute value
	// or yyyymmddhhmmss.mmmmmm:000 for intervals
    	//
	try {
	    int offset=Integer.parseInt(inStr.substring(22,25));
	    char sign=inStr.charAt(21);
	    if (sign==':') {
		if (offset!=0) {
		    // Pam Wright, Imation Change InstantiationError to
		    // IllegalArgumentException InstantiationError did not
		    // get handled properly because it is not an exception
		    // IllegalArgument is a more appropriate class to
		    // characterize the problem.
		    throw new IllegalArgumentException(inStr+" is not a valid CIM interval");
    		}
    	        intervalSet=true;
	    }
	    hours=Integer.parseInt(inStr.substring(8,10));
	    mins=Integer.parseInt(inStr.substring(10,12));
	    secs=Integer.parseInt(inStr.substring(12,14));
	    milliseconds=Integer.parseInt(inStr.substring(15,21));
	    if (!intervalSet) {
		int year=Integer.parseInt(inStr.substring(0,4));
		int month= (Integer.parseInt(inStr.substring(4,6)))-1;
		int day=Integer.parseInt(inStr.substring(6,8));
		if (sign=='+') {
		    UTCoffset=offset;
		} else if (sign=='-') {
		    UTCoffset =-offset;
		} else {
		    // Pam Wright, Imation Change InstantiationError to
		    // IllegalArgumentException InstantiationError did not
		    // get handled properly because it is not an exception
		    // IllegalArgument is a more appropriate class to
		    // characterize the problem.
		    throw new IllegalArgumentException(inStr+" is not a valid CIM date because the UTC must be preceeded by +/-");
		}
		
		cal.setTimeZone(TimeZone.getTimeZone( GREENWICH_MEAN_TIME ));	
		cal.set(year,month,day,hours,mins,secs);
		cal.set(Calendar.MILLISECOND,milliseconds);
		
		realCal=(Calendar)cal.clone();
		realCal.set(Calendar.DST_OFFSET,UTCoffset*UTC_MULTIPLIER);
	    } else {
		days=Integer.parseInt(inStr.substring(0,8));
	    }
	} catch (Exception e) {
	    // Pam Wright, Imation Change InstantiationError to
	    // IllegalArgumentException InstantiationError did not
	    // get handled properly because it is not an exception
	    // IllegalArgument is a more appropriate class to
	    // characterize the problem.
	    throw new IllegalArgumentException(inStr+" is not a valid CIM date");
	}
    }

    
    /**
     * Determines if this instance represents an interval
     * 
     * @return TRUE if this is an interval
     */
    public boolean isInterval() {
    	return(intervalSet);
    }
    
    
    

    /**
     * Returns a string representation of this date/time that is
     * compliant with the CIM specification
     *
     * @return A string that represents a date/time
     */
    public String toString() {
	String sign;
	int offset=0;
	String outputString;

    	if (!intervalSet) {
	    int year=cal.get(Calendar.YEAR);

            // Andrei Viktorov ProdEx Technologies
            // was int month=cal.get(Calendar.MONTH);
            // and return from 0 to 11 for jdk-1.2.2.
	    int month=cal.get(Calendar.MONTH)-cal.getMinimum(Calendar.MONTH)+1;
	    int day=cal.get(Calendar.DAY_OF_MONTH);

            // Andrei Viktorov ProdEx Technologies
            // was hours=cal.get(Calendar.HOUR),
            // because HOUR is used for the 12-hour clock
	    hours=cal.get(Calendar.HOUR_OF_DAY);

	    int mins=cal.get(Calendar.MINUTE);
	    int secs=cal.get(Calendar.SECOND);
	    int milliseconds=cal.get(Calendar.MILLISECOND);
	    //int offsetHours=cal.get(Calendar.ZONE_OFFSET)/(60*60*1000);
	    int offsetHours=UTCoffset;
            // Andrei Viktorov ProdEx Technologies
            // was if (offsetHours<12)
	    if (offsetHours > 0) {
		offset= offsetHours; //cal.get(Calendar.ZONE_OFFSET)/(60*1000);
		sign="+";
	    } else {
                offset= -offsetHours; //- cal.get(Calendar.ZONE_OFFSET)/(60*1000);
		sign="-";
    	    }
	    outputString=padString(year,4);
	    outputString=outputString.concat(padString(month,2));
	    outputString=outputString.concat(padString(day,2));
	} else {
	    outputString=padString(days,8);
	    // Pam Wright, Imation hours was duplicated in interval strings
	    // outputString=outputString.concat(padString(hours,2));
            sign=":";
	}

	outputString=outputString.concat(padString(hours,2));
	outputString=outputString.concat(padString(mins,2));
	outputString=outputString.concat(padString(secs,2));
	outputString=outputString.concat(".");
	outputString=outputString.concat(padString(milliseconds,6));
	outputString=outputString.concat(sign);
	outputString=outputString.concat(padString(offset,3));

	return(outputString);
    }


   /**
    * Returns a string representation of this date/time that is
    * compliant with the CIM specification
    * 
    * @return A string that represents a date/time
    */
    public String toMOF() {
	return(toString());
    }



   /**
    * Determines the date/time of this instance is after that of the
    * instance passed
    * 
    * @param inDate The date to check against
    * @return TRUE if this instance is after that of the instance passed
    */
    public boolean after(CIMDateTime inDate) {
    	//
    	// Return false if either CIMDataTime is an interval
    	//
	if (intervalSet || inDate.intervalSet)
    	    return(false);
	return(realCal.after(inDate.realCal));
    }
    
    
    /**
     * Determines the date/time of this instance is before that of the
     * instance passed
     * 
     * @param inDate The date to check against
     * @return TRUE if this instance is before that of the instance passed
     */
    public boolean before(CIMDateTime inDate) {
    	//
    	// Return false if either CIMDataTime is an interval
    	//		
	if (intervalSet || inDate.intervalSet)
    		return(false);
	return(realCal.before(inDate.realCal));
    }

    
    
    /**
     * Determines the date/time of this instance is equal to that of the
     * instance passed
     * 
     * @param inDate The date to check against
     * @return TRUE if this instance is equal to the instance passed
     */	
    public boolean equals(CIMDateTime inDate) {
	//
	// Look for intervals
	//
	if (intervalSet && inDate.intervalSet) {
	    return( days==inDate.days && hours==inDate.hours
		    && mins==inDate.mins && secs==inDate.secs 
		    && milliseconds==inDate.milliseconds);
    	}
    	//
    	// Check both are not intervals (can't be equal in this case)
    	//
	if (intervalSet || inDate.intervalSet)
	    return(false);
    
    	return(realCal.equals(inDate.realCal));
    }



   /**
    * Returns the calendar being used by this CIMDateTime
    * 
    * @return The current calendar in use
    */
    public Calendar getCalendar() {
	return((Calendar)realCal.clone());
    }
    
   /**
    * Produces a string from an integer of a specified length with
    * leading zeros to pad
    * 
    * @param inVal The integer value to convert
    * @param len The minium length of the String
    * @return The padded string that represents the passed integer
    */
    private String padString(int inVal, int len) {
	String pad=new String("0");	
    String buf=new Integer(inVal).toString();
    	for(int i=buf.length();i<len;i++)
	    buf=pad.concat(buf);
    	return(buf);	
    }
	
    static public void main(String[] args) {
	String in="19980525133015.000000-300";
	CIMDateTime date = new CIMDateTime(in);
		
	System.err.println("In was :"+in);
	System.err.println("Out was:"+date.toString());
	for(;;) {
	}
    }
}
