/*******************************************************************************
**
** Filename:  CMICore.java
**
** File Description:  The CMICore class manages information required
**                    to be furnished by all LMS Systems.  It contains
**                    data that all Assignable Units may depend upon at
**                    startup.
**
** Author: ADLI Project
**
** Company Name: Concurrent Technologies Corporation
**
** Module/Package Name: org.adl.datamodel.cmi
** Module/Package Description: Collection of CMI Data Model objects
**
** Design Issues:
**        In order to use Reflection (Java Feature) the defined Java
**        coding standards are NOT being followed.  Reflection requires
**        field names to match identically to input parameter.  The
**        attribute names match what is expected from a LMSGetValue()
**        or LMSSetValue() request.  Also the attribute values are declared
**        as public scope in order to use reflection.
**
** Implementation Issues:
** Known Problems:
** Side Effects:
**
** References: AICC CMI Data Model
**             ADL SCORM Version 1.1
**
*******************************************************************************
**
** Concurrent Technologies Corporation (CTC) grants you ("Licensee") a non-
** exclusive, royalty free, license to use, modify and redistribute this
** software in source and binary code form, provided that i) this copyright
** notice and license appear on all copies of the software; and ii) Licensee
** does not utilize the software in a manner which is disparaging to CTC.
**
** This software is provided "AS IS," without a warranty of any kind.  ALL
** EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
** IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-
** INFRINGEMENT, ARE HEREBY EXCLUDED.  CTC AND ITS LICENSORS SHALL NOT BE LIABLE
** FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
** DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL CTC  OR ITS
** LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
** INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
** CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
** OR INABILITY TO USE SOFTWARE, EVEN IF CTC HAS BEEN ADVISED OF THE POSSIBILITY
** OF SUCH DAMAGES.
**
*******************************************************************************
**
** Date Changed   Author            Reason for Changes
** ------------   ----------------  -------------------------------------------
** 09/05/2000     ADLI Project      PT110 : Changed the check for CMIString256
**                                          to CMIString255 to reflect the CMI
**                                          3.4 document.
**
** 11/15/2000     S. Thropp         PT 263 - Cosmetic changes to change the
**                                  version number of SCORM.
*******************************************************************************/

package org.adl.datamodels.cmi;

//native java imports
import java.io.*;
import java.lang.reflect.*;

//adl imports
import org.adl.util.debug.*;
import org.adl.datamodels.*;
import org.adl.samplerte.client.APIAdapterApplet;

public class CMICore extends CMICategory
   implements Serializable
{
   // Indicates whether the student is being credited by the LMS for their
   // performance in the AU
   public Element credit;

   // Indication of whether the student has been in the AU before
   public Element entry;

   // Indication of how or why the student left an AU
   public Element exit;

   // Lesson exit point passed to the LMS the last time the student experienced
   // the AU
   public Element lesson_location;

   // Identification of student-related information that may be used to change
   // the behavior of the AU
   public Element lesson_mode;

   // Student status as determined by the LMS
   public Element lesson_status;

   // Indication of the performance of the student during their last attempt on
   // the AU
   public CMIScore score;

   // Time spent in the AU during the session that is ending
   public Element session_time;

   // Unique alpha-numeric identifier that refers to  a single user of the LMS
   public Element student_id;

   // Offical name of the student
   public Element student_name;

   // Accumulated time of all the student sessions in the AU
   public Element total_time;

   // The minimum number of tokens in a valid core Data Model Element
   // request
   static int CMICORE_MIN_NUM_TOKENS = 3;


   /****************************************************************************
    **
    ** Method:  Default constructor
    ** Input:   none
    ** Output:  none
    **
    ** Description:  The default constructor sets up the class and initalizes
    **                all of its attributes.
    **
    **               See Element Constructor for more detail
    ***************************************************************************/
   public CMICore()
   {
      // Set up default values for all attributes

      super( true );
      student_id = new Element("","checkIdentifier","NULL",false,true,true);
      student_name = new Element("","checkString255","NULL",false,true,true);
      lesson_location = new Element("","checkString255","NULL",true,true,true);
      credit = new Element("","checkVocabulary","Credit",false,true,true);
      lesson_status = new Element("","checkVocabulary","Status",true,true,true);
      entry = new Element("","checkVocabulary","Entry",false,true,true);
      total_time = new Element("","checkTimespan","NULL",false,true,true);
      lesson_mode = new Element("","checkVocabulary","Mode",false,true,true);
      exit = new Element("","checkVocabulary","Exit",true,false,true);
      session_time = new Element("","checkTimespan","NULL",true,false,true);
      score = new CMIScore();
   }

   /************************************************************************
    **  Accessers to the CMICore Data.  AUs should not call these methods.
    **  AUs should call LMSGetValue().
    ************************************************************************/
   public Element getCredit()
   {
      return credit;
   }
   public Element getEntry()
   {
      return entry;
   }
   public Element getExit()
   {
      return exit;
   }
   public Element getLessonLocation()
   {
      return lesson_location;
   }
   public Element getLessonMode()
   {
      return lesson_mode;
   }
   public Element getLessonStatus()
   {
      return lesson_status;
   }
   public CMIScore getScore()
   {
      return score;
   }
   public Element getSessionTime()
   {
      return session_time;
   }
   public Element getStudentId()
   {
      return student_id;
   }
   public Element getStudentName()
   {
      return student_name;
   }
   public Element getTotalTime()
   {
      return total_time;
   }

   /************************************************************************
    **  Modifiers to the CMICore Data.  AUs should not call these methods.
    **  AUs should call LMSSetValue()
    ************************************************************************/
   public void setCredit(String inCredit)
   {
      credit.setValue(inCredit);
   }
   public void setEntry(String inEntry)
   {
      entry.setValue(inEntry);
   }
   public void setExit(String inExit)
   {
      exit.setValue(inExit);
   }
   public void setLessonLocation(String inLessonLocation)
   {
      lesson_location.setValue(inLessonLocation);
   }
   public void setLessonMode(String inLessonMode)
   {
      lesson_mode.setValue(inLessonMode);
   }
   public void setLessonStatus(String inLessonStatus)
   {
      lesson_status.setValue(inLessonStatus);
   }
   public void setScore(CMIScore inScore)
   {
      score.getRaw().setValue( inScore.getRaw().getValue() );
      score.getMin().setValue( inScore.getMin().getValue() );
      score.getMax().setValue( inScore.getMax().getValue() );
   }
   public void setSessionTime(String inSessionTime)
   {
      session_time.setValue(inSessionTime);
   }
   public void setStudentId(String inStudentID)
   {
      student_id.setValue(inStudentID);
   }
   public void setStudentName(String inStudentName)
   {
      student_name.setValue(inStudentName);
   }
   public void setTotalTime(String inTotalTime)
   {
      total_time.setValue(inTotalTime);
   }


   /****************************************************************************
    **
    ** Method:  performGet
    ** Input:   CMIRequest theRequest - the LMSGetValue() request
    **          DMErrorManager dmErrorMgr - Error manager, handles all
    **                                        error reporting
    **
    ** Output:  String - the value portion of the element for the LMSGetValue()
    **
    ** Description:  This method performs the LMSGetValue() request.  The method
    **    determines the value for the requested data element.
    **
    ***************************************************************************/
   public String performGet(CMIRequest theRequest,
                            DMErrorManager dmErrorMgr)
   {
      // Resultant value to return
      String result = new String("");

      // Check to make sure this is a valid LMSGetValue() request
      if ( isValidCoreRequest(theRequest) )
      {
         // Get the next token off of the request
         String token = theRequest.getNextToken();

         // Check to see if the Request has more tokens to process
         if ( theRequest.hasMoreTokensToProcess() )
         {
            // Subcategory found in request
            result = processSubcategory(theRequest,token,dmErrorMgr);
         }
         else
         {
            // No more tokes to process

            // Check to see if the request is for the children of Core Data
            if ( theRequest.isAChildrenRequest() )
            {
               // Set result to the string of children
               result = getChildren();
            }
            else
            {
               // determine the value associated with the element requested
               result = determineElementValue(this,token,dmErrorMgr);
            }
         }
      }
      else
      {
         if ( DebugIndicator.ON )
         {
            // Error - Data Model Element not implemented
            System.out.println("Error - Data Model Element not implemented");
            System.out.println("Request being processed: " + theRequest.getRequest() +
                            "\nis not a valid request for the CMI Core\n" +
                            "Data Model Category");
         }

         dmErrorMgr.recNotImplementedError(theRequest);
      }

      // Done getting requested element.  Let the CMIRequest object
      // know that the LMSGetValue() processing is done
      theRequest.done();

      return result;
   }  // end of performGet

   /***************************************************************************
    **
    ** Method:  getChildren
    ** Input:   none
    ** Output:  String representation of the elements of the CMI Core
    **          category
    **
    ** Description:
    **      This method returns a String containing the list of data elements
    **      that CMI Core data object contains.
    **
    ***************************************************************************/
   public String getChildren()
   {
      String children = "student_id,student_name,lesson_location," +
                        "credit,lesson_status,entry,score,total_time,lesson_mode," +
                        "exit,session_time";

      return children;
   }  // end of getChildren

   /****************************************************************************
    **
    ** Method:  performSet
    ** Input:   CMIRequest theRequest - request to process
    **          DMErrorManager dmErrorMgr - Error manager
    **
    ** Output:  none
    **
    ** Description:  This method performs the LMSSetValue() request.
    **
    ***************************************************************************/
   public void performSet(CMIRequest theRequest,
                          DMErrorManager dmErrorMgr)
   {
            
       
       if ( DebugIndicator.ON )
      {
         System.out.println("Within cmicore PERFORMSET with request: " + theRequest);
      }
         
       
      // Check to see if this is a valid LMSSetValue() request
      if ( isValidCoreRequest(theRequest) == true )
      {
         // Get the next token off of the request
         String token = theRequest.getNextToken();

         // Check to see if the request has any more tokens to
         // process
         if ( theRequest.hasMoreTokensToProcess() )
         {
            // More tokens to process - subcategory found
            String result = processSubcategory(theRequest,token,dmErrorMgr);
         }
         else
         {
            //  No more tokens to process

            // Get the value to use for setting off of the request
            String value = theRequest.getValue();

            // Set the value
            if ( theRequest.isAKeywordRequest() )
            {
               dmErrorMgr.recKeyWordError(token);
            }
            else
            {
               // Check to see if the set is for lesson_status
               // SCOs are not permitted to set cmi.core.lesson_status
               // to not attempted
               if (token.equals("lesson_status") )
               {
                   if ( value.equals("not attempted") && APIAdapterApplet.areweloading==false )
                   {
                        System.out.println("I WILL NOT ALLOW RE-SETTING not attempted!!!");
                       dmErrorMgr.SetCurrentErrorCode("405");
                   }
                   else
                   {
                       // Perform the setting of the value
                       doSet(this,token,value,dmErrorMgr);
                   }
               }
               else
               {
                   // Perform the setting of the value
                   doSet(this,token,value,dmErrorMgr);
               }
            }
         }
      }
      else
      {
         if ( DebugIndicator.ON )
         {
            // Error - Data Model Element not implemented
            System.out.println("Error - Data Model Element not implemented");
            System.out.println("Request being processed: " + theRequest.getRequest() +
                            "\nis not a valid request for the CMI Core\n" +
                            "Data Model Category");
         }

         dmErrorMgr.recNotImplementedError(theRequest);
      }

      // Done setting requested element.  Let the request object know
      // that the LMSSetValue() processing is finished
      theRequest.done();

   } // end of performSet

   /****************************************************************************
    **
    ** Method:  processSubcategory
    ** Input:   CMIRequest - the current request being processed
    **          String - the subcategory being processed
    **          DMErrorManager - the Data Model Error Manager
    **
    ** Output: String -  result to be returned.  If the request is for
    **                   an LMSSetValue() request an empty string is
    **                   returned
    **
    ** Description: This method processes the subcategories of the CMICore
    **              Data Model Category.  The only valid subcategory of the
    **              CMI Core class is the CMIScore class.  Any other \
    **              subcategories are invalid - non compliant.
    **
    **              If the request is for an LMSSetValue(), then an empty
    **              String is returned.
    **
    ***************************************************************************/
   private String processSubcategory(CMIRequest theRequest,
                                     String theElement,
                                     DMErrorManager dmErrorMgr)
   {
      String result = new String("");

      try
      {
         Field tmpField = this.getClass().getField(theElement);

         // Call Get or Set on CMIScore
         if ( theRequest.isForASetRequest() )
         {
            // Set the value
            if ( theRequest.isAKeywordRequest() )
            {
               dmErrorMgr.recKeyWordError(theRequest.getElement());
            }
            else
            {
               // Invoke the performSet() on the subcategory
               score.performSet(theRequest,dmErrorMgr);
            }
         }
         else
         {
            if ( theElement.equals("score") )
            {
               result = score.performGet(theRequest,dmErrorMgr);
            }
            else
            {
               dmErrorMgr.recGetKeyWordError(theRequest.getElement());
            }
         }
      }
      catch ( NoSuchFieldException nsfe )
      {
         if ( DebugIndicator.ON )
         {
            // Error - Data Model Element not implemented
            // *** The only subcategory in the CMI Core Data Category
            // *** is the score.  Any thing else is an error
            System.out.println("Error - Data Model Element not implemented");
            System.out.println("Element being processed: " + theElement +
                            "is not a valid sub category of the CMI Core\n" +
                            "Data Model Category");
         }

         dmErrorMgr.SetCurrentErrorCode("401");
      }
      catch ( SecurityException se )
      {
         if ( DebugIndicator.ON )
         {
            System.out.println(se);
            System.out.println("Access to the information is denied");
         }
         dmErrorMgr.SetCurrentErrorCode("101");
      }

      return result;
   }

   /****************************************************************************
    **
    ** Method:  isValidCoreRequest
    ** Input:   CMIRequest theRequest - the LMSGetValue() request
    **
    ** Output:  Boolean value indicating whether or not the Core Request is
    **          valid.
    **
    ** Description:  Checks to make sure that the request meets the minimum
    **               requirements needed for a CMICore Model Element.
    **
    ***************************************************************************/
   private boolean isValidCoreRequest(CMIRequest theRequest)
   {
      boolean rtrnFlag = false;

      // Check to see if the Request has the appropriate length for
      // a CMI Core request
      if ( theRequest.getTotalNumTokens() >= CMICORE_MIN_NUM_TOKENS )
      {
         rtrnFlag = true;
      }

      return rtrnFlag;

   } // end of isValidCoreRequest()

   /****************************************************************************
    **
    ** Method:  showData
    ** Input:   none
    ** Output: none
    **
    ** Description: Displays the current state of the CMI Core Data object
    **
    ***************************************************************************/
   public void showData()
   {
      if ( DebugIndicator.ON )
      {
         System.out.println("CMI Core Object:");

         System.out.println("\tstudent_id: " + getStudentId().getValue());
         System.out.println("\tstudent_name: " + getStudentName().getValue());
         System.out.println("\tlesson_location: " + getLessonLocation().getValue());
         System.out.println("\tcredit: " + getCredit().getValue());
         System.out.println("\tslesson_status: " + getLessonStatus().getValue());
         System.out.println("\tentry: " + getEntry().getValue());
         System.out.println("\texit: " + getExit().getValue());
         System.out.println("\tscore.raw: " + getScore().getRaw().getValue());
         System.out.println("\tscore.min: " + getScore().getMin().getValue());
         System.out.println("\tscore.max: " + getScore().getMax().getValue());
         System.out.println("\tsession_time: " + getSessionTime().getValue());
         System.out.println("\ttotal_time: " + getTotalTime().getValue());
         System.out.println("\tlesson_mode: " + getLessonMode().getValue());
      }
   }
}  // end of CMICore
