/*=========================================================================

  Program:   Orbit Visualization Tool
  Source:    $Source: /stor/devel/ovt2g/ovt/datatype/TleRecord.java,v $
  Date:      $Date: 2000/06/14 13:50:01 $
  Version:   $Revision: 1.10 $


Copyright (c) 2000 OVT Team (Kristof Stasiewicz, Mykola Khotyaintsev, 
Yuri Khotyaintsev)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification is permitted provided that the following conditions are met:

 * No part of the software can be included in any commercial package without
written consent from the OVT team.

 * Redistributions of the source or binary code must retain the above
copyright notice, this list of conditions and the following disclaimer.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT OR
INDIRECT DAMAGES  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE.

OVT Team (http://ovt.irfu.se)   K. Stasiewicz, M. Khotyaintsev, Y.
Khotyaintsev

=========================================================================*/

package ovt.datatype;

//import ovt.object.*;

//@author KONO

public class TleRecord{
   //Math.toRadians appeared only since JDK 1.2
   public static double toRad=0.017453293F;
   // 0th line (name), length<=24, all other lines <=69
   public String satName=new String();
   // 1st line
   public final byte lineNum1=1;         //01
   public int satNumber1;                //03-07
   public char type;                     //08
   public int launchYear;               //10-11
   public int launchNumOfYear;           //12-14
   public char[] pieceLaunch=new char[3];//15-17
   public int epochYear;                //19-20
   public double epochDay;                //21-32
   public double fstTimeDerivOfMeanMotion;//34-43
   public double sndTimeDerivOfMeanMotion;//45-52*
   public double bstar;                   //54-61*
   public byte ephemerisType;            //63,1-SGP,2-SGP4,3-SDP4,4-SGP8,5-SDP8
   public int elemNumber;                //65-68
   public byte checkSum1;                //69,modulo 10      
   // 2nd line
   public final byte lineNum2=2;         //01
   public int satNumber2;                //03-07
   public double incl;                    //09-16,degs
   public double ascenOfNode;             //18-25,degs
   public double eccentricity;            //27-33,after 0. ...
   public double argOfPerigee;            //35-42,degs
   public double meanAnomaly;             //44-51,degs
   public double meanMotion;              //53-63,revs/day
   public int revNum;                    //64-68,revs
   public byte checkSum2;                //69,modulo 10

   public TleRecord(){
   }

   public TleRecord(String ss){
      setLine(ss);
   }
   
   public TleRecord(String l1, String l2){ //set data records (both lines)
      setLine(l1);
      setLine(l2);
   }

   public TleRecord(String l0, String l1, String l2){ //name + data lines
      setLine(l0);
      setLine(l1);
      setLine(l2);
   }

   /** Processing of line from TLE data files
    * @param strX Input string
    * @return 0 if success or -1 if error
    */
   public byte setLine(String strX){
      byte id=TleRecord.identLine(strX);
      char ch;
      int i,chksum=0;

      if(id==-1){
         return id;
      }

      for(i=0;i<(strX.length()-1);++i){ //Calculating checksum
         ch=strX.charAt(i);
         if(ch>='0' && ch<='9')
            chksum+=ch-'0';
         else if(ch=='-')
            ++chksum;
      }
      chksum%=10;
      try {
         switch(id){
            case -1:
               return -1;
            case 0:
               satName=new String(strX);
               return 0;
            case 1:
               satNumber1=new Integer(numSubstring(strX,2,7)).intValue();
               type=strX.charAt(7);
               launchYear=new Integer(numSubstring(strX,9,11)).intValue();
               launchYear=Y2K(launchYear);
               launchNumOfYear=new Integer(numSubstring(strX,11,14)).intValue(); //!!!
               for(i=14;i<17;++i)
                  pieceLaunch[i-14]=strX.charAt(i);
               epochYear=new Integer(numSubstring(strX,18,20)).intValue();
               epochYear=Y2K(epochYear);
               epochDay=new Double(numSubstring(strX,20,32)).doubleValue();
               fstTimeDerivOfMeanMotion=new Double(numSubstring(strX,33,43)).doubleValue();
               sndTimeDerivOfMeanMotion=modifyExpFmt(strX.substring(44,52));
               bstar=modifyExpFmt(strX.substring(53,61));
               ephemerisType=new Byte(numSubstring(strX,62,63)).byteValue();
               elemNumber=new Integer(numSubstring(strX,64,68)).intValue();
               checkSum1=new Byte(numSubstring(strX,68,69)).byteValue();
               break;
            case 2:
               satNumber2=new Integer(numSubstring(strX,2,7)).intValue();
               incl=new Double(numSubstring(strX,8,16)).doubleValue()*toRad;
               ascenOfNode=new Double(numSubstring(strX,17,25)).doubleValue()*toRad;
               eccentricity=new Double("0."+strX.substring(26,33)).doubleValue();
               argOfPerigee=new Double(numSubstring(strX,34,42)).doubleValue()*toRad;
               meanAnomaly=new Double(numSubstring(strX,43,51)).doubleValue()*toRad;
               meanMotion=new Double(numSubstring(strX,52,63)).doubleValue();
               revNum=new Integer(numSubstring(strX,63,68)).intValue();
               checkSum2=new Byte(numSubstring(strX,68,69)).byteValue();
               break;
            default:
               System.err.println("TleRecord.setLine: Unknown identLine code!");
               return -1;                    //strange error
         }
      } catch (NumberFormatException e){
         System.err.println("Invalid number format in TLE record: "+strX);
         return -1;
      }
/*      if(chksum!=(id==1?checkSum1:checkSum2)){
         System.err.println("Bad checksum in line: "+strX);
         return -1;
      }*/

      return 0;
   }
   /** Identification of lines from TLE data files
    * @param strX Input string
    * @return TLE record line number (0..2) or -1 if error
    */
   public static byte identLine(String strX){
   //Returns 0, 1 or 2 (line number) or -1 if any error
/*      if(strX.length()>69){
         System.err.println("TleRecord.setLine: Invalid identLine code!");
         return -1;                         // ERROR: too long string
      } else*/ if(strX.length()<69)
         return 0;                          //probably line 0
      char lineID=strX.charAt(0);
      switch(lineID){
         case '1': return 1;
         case '2': return 2;
         default: return -1;
      }
   }
   
   /** Converts moified exponential format: 102034-01 -> 0.102034e-01
    * @param String ss - Input string
    * @return double value
    */
   public static double modifyExpFmt(String ss){
      double mantissa=0.0, exp,sign=1.0,pow=1.0;
      char cc;

      for(int i=0;i<6;++i){
         cc=ss.charAt(i);
         if(cc=='0' || cc=='1' || cc=='2' || cc=='3' || cc=='4' || 
         cc=='5' || cc=='6' || cc=='7' || cc=='8' || cc=='9'){
            pow*=0.1;
            mantissa+=pow*(cc-'0');
         } else if(cc=='-'){
            sign=-1;
         } else if(cc=='+'){
            sign=1;
         }
      }
      exp=new Double(ss.substring(ss.length()-2,ss.length())).doubleValue();
      exp=Math.pow(10.0,exp);
      return sign*mantissa*exp;
   }
   
   public static String numSubstring(String str,int beg, int end){
      String res=new String(str.substring(beg,end));
      return res.replace(' ','0');
   }
   
   public static int Y2K(int yy){
      int xx=yy>50?1900:2000; //Y2K :-)
      return (yy<1950)?yy+xx:yy;
   }

   public TleRecord cloneMe(){
      TleRecord tmp=new TleRecord();
      
      if(satName.length()>0)
         tmp.satName=new String(satName);
      tmp.satNumber1=satNumber1;
      tmp.type=type;
      tmp.launchYear=launchYear;
      tmp.launchNumOfYear=launchNumOfYear;
      for(byte i=0;i<3;++i)
         tmp.pieceLaunch[i]=pieceLaunch[i];
      tmp.epochYear=epochYear;
      tmp.epochDay=epochDay;
      tmp.fstTimeDerivOfMeanMotion=fstTimeDerivOfMeanMotion;
      tmp.sndTimeDerivOfMeanMotion=sndTimeDerivOfMeanMotion;
      tmp.bstar=bstar;
      tmp.ephemerisType=ephemerisType;
      tmp.elemNumber=elemNumber;
      tmp.checkSum1=checkSum1;
      tmp.satNumber2=satNumber2;
      tmp.incl=incl;
      tmp.ascenOfNode=ascenOfNode;
      tmp.eccentricity=eccentricity;
      tmp.argOfPerigee=argOfPerigee;
      tmp.meanAnomaly=meanAnomaly;
      tmp.meanMotion=meanMotion;
      tmp.revNum=revNum;
      tmp.checkSum2=checkSum2;
      return tmp;
   }
   
   public void printAll(){
      print1stLine();
      print2ndLine();
   }
   
   public void print1stLine(){
      System.out.print(new Byte(lineNum1).toString()+',');
      System.out.print(satNumber1+",");
      System.out.print(String.valueOf(type)+',');
      System.out.print(launchYear+",");
      System.out.print(launchNumOfYear+",");
      System.out.print(new String(pieceLaunch)+",");
      System.out.print(epochYear+",");
      System.out.print(epochDay+",");
      System.out.print(fstTimeDerivOfMeanMotion+",");
      System.out.print(sndTimeDerivOfMeanMotion+",");
      System.out.print(bstar+",");
      System.out.print(new Byte(ephemerisType).toString()+",");
      System.out.print(elemNumber+",");
      System.out.println(new Byte(checkSum1).toString());
   }

   public void print2ndLine(){
      System.out.print(lineNum2+",");
      System.out.print(satNumber2+",");
      System.out.print(incl/toRad+",");
      System.out.print(ascenOfNode/toRad+",");
      System.out.print(eccentricity+",");
      System.out.print(argOfPerigee/toRad+",");
      System.out.print(meanAnomaly/toRad+",");
      System.out.print(meanMotion+",");
      System.out.print(revNum+",");
      System.out.println(checkSum2);

   }
}
