;+
; Project     :	SOHO - CDS
;
; Name        :	CPT_ALTS
;
; Purpose     :	Prepares the CDS command tables for the alternative science plan.
;
; Explanation :	This routine interrogates the databases describing the alternative science plan
;               and produces the tables needed to implement the plan on the CDS.
;
;               Studies in the sci_alt database provide an alternative time line to the details 
;               database studies. The alternative studies are standalone (akin to flag studies)
;               and must :
;                   -- have no repeat study;
;                   -- have no repeat pointings;
;                   -- cannot contain flag studies.
;
;               The initial state ie. the start parameters for the study including :
;               GIS look up table, slit number, OPS pos ; must be
;               reached by command from the ground so that the current state 
;               does not affect the series table.
;               
;               In the series_id database each study is labelled 
;               by its initial pointing and deferred pointing. These are zero for 
;               an alternative study.  
;               Only studies with the same initial and deferred pointings are re-usable in the sense
;               of not having to load the series tables onto the CDS spacecraft again.
;
;               Studies are also labelled by the sequential study ID which is the CDHS ID of the next study
;               following sequentially. This field is set to -1 (=#FFFF which is not a valid CDHS ID).
;
;               Engineering studies are valid alternative studies.
;
;               NB If the main science plan is to be resumed then :
;                  the pointing and slit number must be unchanged;
;                  the GSETID parameters must be unchanged.
;
;               If raster, dexwin or vdswin tables have previously been encountered they will not be 
;               processed again. The times associated with the commprep database entries will be the
;               first encountered i.e the latest since processing is performed in reverse time order.    
;
;               Series tables, raster tables, vdswin tables and dexwin tables are not reusable 
;               between main science plan, alternative science plan and flag studies (for programming
;               convenience only).
;
;               Standalone studies have FIXED, DEFERRED or EVENT pointing.
;                 FIXED if study does not contain rasters with deferred pointing.
;                 DEFERRED if study contains rasters with deferred pointing and 
;                          details.n_pointings <> 0
;                 EVENT if study contains rasters with deferred pointing and 
;                          details.n_pointings = 0
;              
;               Flag studies must have only one raster since CPT puts commands to 
;               insert things into the series table and start position not necessarily 
;               known.
;               Alternative studies may have more than one raster, but if use relative 
;               then first raster must have FIXED or DEFERRED pointing not EVENT pointing.
; 
; Use         :	<cpt_alts, ltb_unit, details_list, series_list, cut_off_time> 
;
; Inputs      :	ltb_unit       : logical unit for LTB file
;               details_list       : structure array of studies from altplan_details database.
;               cut_off_time   : DOUBLE TAI format time before which tables may be overwritten
;
; Opt. Inputs : None.
;
; Outputs     : Produces the various CVT files needed for the science plan.
;
; Opt. Outputs:	None.
;
; Keywords    :	None.
;
; Calls       :	get_detail, get_study, get_raster, get_datawin,
;               get_series_info, get_raster_info,
;               get_dexwin_info, get_vdswin_info,
;               wr_vdswin_file, wr_dexwin_file, wr_raster_file, wr_series_file,
;               wr_ltb, anytim2cal, set_exposure, update_dex, nxt_series_id, fix_series_id.
;                
; Common      :	None.
;
; Restrictions:	None.
;
; Side effects:	None.
;
; Category    :	Command preparation.
;
; Prev. Hist. :	None.
;
; Written     :	Version 0.0, Martin Carter, RAL, 20/4/98
;                            Adapted from cpt_details.
;
; Modified    :	Added decimal CDHS ID in print out.  CDP, 3-Jun-98
;               Version 0.2 , MKC, 18/6/98
;                 Added ALTSCI keyword to wr_series_file to comment out mirror and slit initial positions.   
;
; Version     :	Version 0.2, 18/6/98
;-
;**********************************************************

PRO cpt_alts, ltb_unit, details_list, cut_off_time

  ; set no. of studies 

  ndetails = N_ELEMENTS(details_list)

  ; get next SERIES CDHS ID

  series_cdhsid = nxt_series_id()

  ; write out CDHSID data to LTB file

  PRINTF, ltb_unit, '# List of CDHS IDs corresponding to alt_details studies
  PRINTF, ltb_unit

  ; loop through studies within next CDS period in reverse order

  FOR stdn = 0, ndetails-1 DO BEGIN

    ; reverse processing order

    stdyno = ndetails - 1 - stdn 

    PRINT, ''
    PRINT, 'ALTERNATIVE STUDY ', stdyno
    PRINT, ''

    ; get alternative study details    

    altplan_details = details_list(stdyno)

    ; NB planning software does not at present support deferred pointing for
    ;    alternative studies and sets n_pointings = 1.
    ;    Force any deferred pointing to be treated as event pointing
    
    altplan_details.n_pointings = 0

    ; print some study details

    PRINT, 'STUDY OBJECTIVE     : ', altplan_details.sci_obj
    PRINT, 'TIME OF OBSERVATION : ', ANYTIM2CAL ( altplan_details.start_time )
    PRINT, ''
    
    ; perform any checks on altplan_details

    IF altplan_details.n_repeat_s NE 1 THEN $
      MESSAGE, 'ALTERNATIVE STUDY MUST HAVE N_REPEAT_S = 1'

    ; extract study parameters (changed to use GET_CDS_STUDY by DMZ)

    study_details = get_cds_study ( altplan_details.study_id, altplan_details.studyvar)

    ; perform any checks on study_details

    IF ( study_details.usable NE 'Y' ) THEN MESSAGE, 'Study not usable'

    ; perform checks if engineering study

    IF study_details.study_id EQ 0 THEN BEGIN

      ; engineering study
      ; alternative study must have n_repeat_s=1 and n_pointings=0 anyway

      ; check default no. of rasters

      IF study_details.n_raster_def NE 0 THEN $
         MESSAGE, 'TOO MANY RASTERS FOR ENGINEERING STUDY = ' + STRTRIM( study_details.n_raster_def,2 )

    ENDIF

    ; set up no. of non-repeated rasters
    ; check first if special study 

    IF study_details.n_raster_def EQ 0 THEN BEGIN
      
      ; avoid raster loop

      nrasters = 0 

      rasters  = 0 

    ENDIF ELSE BEGIN

      ; loop through rasters

      nrasters = N_ELEMENTS ( study_details.rasters )

      rasters  = REPLICATE ( {RASTER_STRUCTURE}, nrasters )

      FOR rstrno = 0, nrasters-1 DO BEGIN  

        ; set up no. of times to execute raster

        repn = study_details.rasters(rstrno).n_repeat_r

        ; check sensible no. of rasters

        IF repn LE 0 THEN $
	   MESSAGE, 'Invalid raster repeat number =' + STRTRIM ( repn, 1)

        ; if last raster set repn to n_rasters1

        IF (rstrno EQ nrasters-1) THEN $
	  repn = altplan_details.n_rasters1

        ; check if raster already in raster list
        ; check raster id, var, repn

        raster_index = -1

        IF N_ELEMENTS(raster_list) GT 0 THEN BEGIN

          idlist = WHERE ( raster_list.id EQ study_details.rasters(rstrno).ras_id, count )

          IF count GT 0 THEN BEGIN

            varlist = WHERE ( raster_list(idlist).var EQ study_details.rasters(rstrno).ras_var, count )

            IF count GT 0 THEN BEGIN

              repnlist = WHERE ( raster_list(idlist(varlist)).repn EQ repn, count )

              IF count GT 0 THEN raster_index = idlist(varlist(repnlist(0)))
    
            ENDIF

          ENDIF

        ENDIF 

        ; check if first time raster encountered

        IF raster_index LT 0 THEN BEGIN

          ; get raster details (changed to use GET_CDS_RASTER by DMZ)

          raster_details = get_cds_raster ( study_details.rasters(rstrno).ras_id, $
                                            study_details.rasters(rstrno).ras_var)

          ; set up known raster table parameters

          raster = {RASTER_STRUCTURE}

          raster.id   = study_details.rasters(rstrno).ras_id
          raster.var  = study_details.rasters(rstrno).ras_var
          raster.time = altplan_details.start_time         

          ; save detector  

          raster.detector = raster_details.detector

          ; set up VDS and GIS exposure time and units

          set_exposure, raster_details.exptime, raster

          ; save slit number

          raster.slitn = raster_details.slit_num

          ; check slit number valid

          IF (raster.slitn LT 1) OR (raster.slitn GT 6) THEN $
            MESSAGE, 'Invalid slit number used : ' + STRTRIM ( raster.slitn, 1)

          ; write mirror and slit spans to raster structure
          ; NB x/y steps from planning database are in arcsecs rather than steps
          ;    spans are translated into steps

          raster.mirrorspan = ((raster_details.nx-1)*raster_details.xstep)/2

          raster.slitspan   = (raster_details.ny-1)*raster_details.ystep

          ; set up no. of times to execute raster

          raster.repn = repn

          ; check if raster table already loaded for this study and get table info

          get_raster_info, raster, cut_off_time

          ; check if dexwin already in dexwin list
          ; check dexwin id

          dexwin_index = -1

          IF N_ELEMENTS(dexwin_list) GT 0 THEN BEGIN

            idlist = WHERE ( dexwin_list.id EQ raster_details.dw_id, count )

            IF count GT 0 THEN dexwin_index = idlist(0)

          ENDIF 

          ; check if first time dexwin encountered

          IF dexwin_index LT 0 THEN BEGIN

            ; get data extraction window list details

            get_datawin, raster_details.dw_id, dexwin_details
 
            ; set up known dexwin table parameters

            dexwin = {DEXWIN_STRUCTURE}

            dexwin.id   = raster_details.dw_id
            dexwin.time = altplan_details.start_time

            ; modify dexwin values to reflect calibration
            ; get calibration version number
         
            dexwin_details = update_dex ( dexwin_details, GSET_ID = details_list(stdyno).gset_id, VERSION = calibration_version ) 

            dexwin.version = calibration_version

            ; check if GIS detector

            IF raster.detector NE 'N' THEN dexwin.gis(dexwin_details.wins.win_def(0)/2048) = 1

            ; check if dexwin table already loaded for this study and get table info

            get_dexwin_info, dexwin, cut_off_time
   
            ; write out dexwin CVT file

            wr_dexwin_file, dexwin, dexwin_details

          ENDIF ELSE BEGIN

            ; dexwin previously encountered

            dexwin = dexwin_list(dexwin_index)

          ENDELSE

          ; set up dexwin list and increment current position

          IF N_ELEMENTS(dexwin_list) EQ 0 THEN dexwin_list = [ dexwin ] $
                                          ELSE dexwin_list = [ dexwin_list, dexwin ]

          ; check if NIS detector

          IF raster.detector EQ 'N' THEN BEGIN

            ; check if vdswin already in vdswin list
            ; check vdswin id not set up
  
            vdswin_index = -1

            IF N_ELEMENTS(vdswin_list) GT 0 THEN BEGIN

              idlist = WHERE ( vdswin_list.id EQ dexwin.id, count )

              IF count GT 0 THEN vdswin_index = idlist(0)

            ENDIF 
        
            ; check if first time vdswin encountered

            IF vdswin_index LT 0 THEN BEGIN

              ; check if vds windows loaded

              ; set up known vdswin table parameters

              vdswin = {VDSWIN_STRUCTURE}

              vdswin.id      = dexwin.id
              vdswin.time    = altplan_details.start_time
              vdswin.version = dexwin.version
              vdswin.iefid   = 0

              ; check if vdswin table already loaded for this study and 
              ; get table info
  
              get_vdswin_info, vdswin, cut_off_time

              ; write out vdswin CVT file

              wr_vdswin_file, vdswin, dexwin_details, 0

            ENDIF ELSE BEGIN

              ; vdswin previously encountered
  
            vdswin = vdswin_list(vdswin_index)

            ENDELSE

            ; set up vdswin list and increment current position

            IF N_ELEMENTS(vdswin_list) EQ 0 THEN vdswin_list = [ vdswin ] $
                                            ELSE vdswin_list = [ vdswin_list, vdswin ]

            ; set up more raster parameters

            raster.vdswid = vdswin.cdhsid

          ENDIF ELSE BEGIN

            ; GIS detector
  
            ; check which GIS detectors in use

            raster.gis = dexwin.gis 

          ENDELSE

          ; set up more raster parameters

          raster.dexwid = dexwin.cdhsid

          ; write out raster CVT file

          wr_raster_file, raster, raster_details

          ; add raster to rasters array

          rasters(rstrno) = raster

        ENDIF ELSE BEGIN

          ; raster previously encountered
          ; add raster to rasters array

          rasters(rstrno) = raster_list(raster_index)

        ENDELSE

        ; add raster to raster list

        IF N_ELEMENTS(raster_list) EQ 0 THEN raster_list = [ rasters(rstrno) ] $
                                        ELSE raster_list = [ raster_list, rasters(rstrno) ]
      ENDFOR
                                      
      ; save raster pointings (not used to define raster)
      ; NB must be done outside of raster loop since raster may already have been used 
      ;    but may have different pointing

      rasters.solx     = study_details.rasters.ins_x
      rasters.soly     = study_details.rasters.ins_y

    ENDELSE

    ; set up known series table parameters

    series = {SERIES_STRUCTURE}

    series.id   = altplan_details.study_id
    series.var  = altplan_details.studyvar   
    series.time = altplan_details.start_time 

    ; set flag study tag i.e a standalone study

    series.flagst = 'Y'
    
    ; no need to set up range 

    ; no emergency study turn off repeat tag

    series.rpt = 'N'

    ; set no. of times to repeat last raster and IEF flags if science study

    IF study_details.n_raster_def NE 0 THEN series.repn = raster.repn
 
    ; check if solar feature tracking required

    IF altplan_details.tracking THEN series.sft  = 'Y' ELSE series.sft  = 'N'

    ; set not time tagged so doesnt get written to deferred store in TTC file

    series.tt = 0

    ; check for deferred raster pointings

    list = WHERE ( study_details.rasters.pointing EQ 1, count )

    ; check if study has rasters using deferred pointing

    IF count GT 0 THEN BEGIN

      IF altplan_details.n_pointings NE 0 THEN BEGIN

        ; pointing is DEFERRED

        series.dsolx = altplan_details.pointings(0).ins_x
        series.dsoly = altplan_details.pointings(0).ins_y
 
        rasters(list).solx = series.dsolx
        rasters(list).soly = series.dsoly

      ENDIF 
      
    ENDIF 
    
    ; check for relative raster pointings
    ; NB does not check for EVENT pointing where first raster pointing
    ;    is not defined.

    list = WHERE ( study_details.rasters.pointing EQ -1, count )

    IF count GT 0 THEN BEGIN

      ; relative pointing defined within the raster
      ; NB pointing now defined relative to the first raster in the study
      ; which has fixed or deferred pointing.
          
      rasters(list).solx = rasters(0).solx + rasters(list).solx
      rasters(list).soly = rasters(0).soly + rasters(list).soly

    ENDIF 
    
    ; check if special study (with n_raster_def=0)

    IF study_details.n_raster_def NE 0 THEN BEGIN

      ; study is normal study

      ; set slit number 

      series.istate.slitn  = raster.slitn

      ; set up GSETID for study
      ; istate.gsetid and fstate.gsetid will be the same if GIS raster involved
      ; NB sw uses gset_id=0 as null gset_id for VDS 
      ;    planning sw uses gset_id=-1 but this only encountered here

      series.istate.gsetid = details_list(stdyno).gset_id > 0

      ; set pointing

      series.istate.solarx = rasters(0).solx
      series.istate.solary = rasters(0).soly

    ENDIF ; else leave all state parameters as zero

    ; set current state equal to initial state
    
    series.fstate = series.istate

    ; series is reusable

    series.reus = 'Y'

    ; bypass check for series table loaded 

    series.cdhsid = series_cdhsid

    ; don not set up following study id -- not needed

    ; check if series table already loaded for this study and 
    ; get table info 
    ; NB may return array of series structures.

    get_series_info, series, cut_off_time

    ; set up dummy following series structure
    
    fseries = {SERIES_STRUCTURE}

    fseries.tt = 1 ; ie next study does not follow sequentially

    ; write out series CVT file 
    ; NB may return array of series structures

    wr_series_file, series, fseries, altplan_details, study_details, rasters, cut_off_time, /ALTSCI

    ; increment series cdhs id

    series_cdhsid = series_cdhsid + N_ELEMENTS(series)

    ; printout no. of series uses

    PRINT, 'NO. OF SERIES TABLES USED = ', STRTRIM(N_ELEMENTS(series),1)
    PRINT, ''

    ; add to series list 

    IF N_ELEMENTS(series_list) EQ 0 THEN series_list = [ series ] $
                                    ELSE series_list = [ series_list, series ]

    ; write out CDHS ID to ltb file.

    PRINTF, ltb_unit, '# CDHS ID = ',shorthex(series(0).cdhsid)+$
                      ' ('+trim(series(0).cdhsid)+')', $
                      ' Study ID = ', STRTRIM ( study_details.study_id, 1), $
                      ' Study var= ', STRTRIM ( study_details.studyvar, 1), $
                      ' obs_prog = ', STRTRIM ( study_details.obs_prog, 1)

  ENDFOR ; end of loop over details list of studies

  ; update series_id database in one go

  fix_series_id, series_list

  ; write out LTB file
  ; overwrites any existing file 

  PRINTF, ltb_unit
  PRINTF, ltb_unit, '# List of table indeces for alt_details studies
  PRINTF, ltb_unit

  ; write out lists of tables used and to be loaded

  IF N_ELEMENTS ( series_list ) GT 0 THEN wr_ltb, ltb_unit, series_list, 'SERIES', 'NEWSERIES'
  IF N_ELEMENTS ( raster_list ) GT 0 THEN wr_ltb, ltb_unit, raster_list, 'RASTER', 'NEWRASTER'
  IF N_ELEMENTS ( dexwin_list ) GT 0 THEN wr_ltb, ltb_unit, dexwin_list, 'DEXWIN', 'NEWDEXWIN'
  IF N_ELEMENTS ( vdswin_list ) GT 0 THEN wr_ltb, ltb_unit, vdswin_list, 'VDSWIN', 'NEWVDSWIN'

END
