indexing
  description: "Logical class used to read and write data Hall of Fame data from and to the file."

class HALL_OF_FAME_FILE

inherit
  PUZZLE_COMPONENT

creation
  make

feature{NONE} -- private

  make is
  do
    file_name := get_hall_of_fame_file_name
    create file.make( hall_of_fame_folder + file_name )
    file_is_present := file.exists
    create file_data.make
    if file_is_present then
      read_hall_of_fame_data
      check_for_BAD_data_discovery
    end
  ensure
    file_data_ready: file_data /= Void
  end

  read_hall_of_fame_data is
  do
    file.open_read
    file.next_line -- skip over the first line
     -- read the file contents here and load up "file_data"
     -- display a warning message if there is trouble reading the data
    from until file.exhausted loop
      file.read_line
      parse_line( file.last_string )
    end
    file.close
   ensure
    file_is_closed: file.is_closed
  end

  check_for_BAD_data_discovery is
  -- If bad HOF data has been discovered, then notify the user and take appropriate action
  do
    if ( bad_HOF_data ) then
      bad_HOF_data := False
      mark_HOF_file( "BAD_", "_BAD" )
      display_bad_HOF_data_message
      -- Data has changed since puzzles with bad HOF entries have been omitted
      file_data.set_data_changed( True )
    else
      -- Data read in was good. Note reading in HOF data changes the boolean "data_changed" in 
      -- HALL_OF_FAME to true so I have to reset if to false if the data read was good.
      file_data.set_data_changed( False )
    end
  end

  hall_of_fame_folder : STRING is
  do
    Result := clone( configuration.hall_of_fame_folder )
  end

  get_hall_of_fame_file_name : STRING is
  do
    Result := clone( configuration.hall_of_fame_file_name )
  end

  in_file_warning_mess : STRING is "WARNING: Editing this file will cause loss of HOF data!"

  file_name, key : STRING
  -- File name for the Hall Of Fame data
  -- The key for the hash table

  value : HALL_OF_FAME_ENTRY_COLLECTION
  -- Sorted list containing the HOF entries

  file : PLAIN_TEXT_FILE
  -- File containg the Hall Of Fame data

  file_is_present, bad_HOF_data : BOOLEAN
  -- Is the file present in the folder?
  -- Has the HOF data in the file been externally modified?

  check_sum : INTEGER
  -- sum of the character codes for a collection of HOF entries in the file

  parse_line( s : STRING ) is
  require
    proper_parameter: s /= Void
  local
    c : CHARACTER
    hofe : HALL_OF_FAME_ENTRY
  do
    c := s.item(1)
    inspect c
    when '[' then  -- File name
      -- strip off enclosing brakets from puzzle name
      key := s.substring( 2, s.count-1 )
      -- get ready for a new collection HOF entries
      create value.make
    when '{' then  -- Check sum 
      check_sum := ( s.substring( 2, s.count-1) ).to_integer
      if validate_check_sum then
        file_data.add_value( value, key )
      end
    else -- Score and user data format
      if valid_entry_string( s ) then
        create hofe.make( ( s.substring( 1, 7 ) ) )
        hofe.add_user_data( s.substring( 9, s.count ) )
        value.add_entry( hofe )
      end
    end
  end

  display_bad_HOF_data_message is
  local
    wmb : WEL_MSG_BOX
  do
    create wmb.make
    wmb.error_message_box( Void, "Hall of Fame data has been modified!%NThe affected data has been deleted." , "Bad Hall Of Fame Data" )
  end

  mark_HOF_file( pre, suf : STRING ) is
  do
    if ( pre /= Void and suf /= Void ) then
      file.change_name( hall_of_fame_folder + pre + file_name + suf )
    elseif ( pre /= Void ) then
      file.change_name( hall_of_fame_folder + pre + file_name )
    elseif ( suf /= Void ) then
      file.change_name( hall_of_fame_folder + file_name + suf )
    end
  end
  
feature{NONE} -- File validation

  valid_entry_string( s : STRING ) : BOOLEAN is
  -- Is the string a valid HOF Entry
  -- Note that a blank name is not possible through INPUT_DIALOG_BOX but
  -- the HOF file may be altered externally which will be caught by the check sum causing all
  -- HOF entries for the puzzle to be eliminated. This routine prevents problems mainly with
  -- the time value since the routine substring handles indixes whihc are out of range.
  -- 0:00:00 user data
  -- 123456789
  local
    time_value : TIME_VALUE
  do
    -- strip off white space
    s.left_adjust
    s.right_adjust
    if s.count > 8 then
      create time_value
      Result := time_value.valid_time_value_string( s.substring( 1, 7 ) )
    end
  end

  validate_check_sum : BOOLEAN is
  -- Obtain check sum and compare to that from the file
  do
    if ( calculate_check_sum ( key + value.out ) /= check_sum ) then
      bad_HOF_data := True 
    else
      Result := True
    end
  end

  calculate_check_sum( s : STRING ) : INTEGER is
  -- Sum the character code for every letter and for every number in the string
  -- Unicode: 0-9-...-A-Z-a-z where 0 is 0x0030 (48), A is 0x0041 (65) and a is 0x0061 (97)
  -- Make sure that check sum rolls over if it exceeds the maximum
  -- 2 byte signed range is -32768 to 32767 for two's compliment
  local
    index : INTEGER
    c : CHARACTER
  do
    from index := 1 until index > s.count loop
      c := s.item( index )
      if ( c.is_alpha or c.is_digit ) then
        Result := ( Result + c.code - 46 ) \\ 32000 -- just to be safe
      end
      index := index + 1
    end
    Result := ( Result + 19 ) \\ 32000 -- just to be safe 
  ensure
    proper_check_sum: Result > -1 and Result < 32000
  end

feature{NONE} -- Modify Hall Of Fame Data

-- Possible Spring 2001 Assignment

  merge_data( d : HALL_OF_FAME ) is
  -- Merge the Hall Of Fame data with existing files in a selected folder
  -- Ensure that you retain only the five best scores from all the files
  do
  end

feature -- public

  file_data : HALL_OF_FAME
  -- Data structure containing the Hall Of Fame data from the file

  write_hall_of_fame_data( d : HALL_OF_FAME ) is
  require
    proper_data: d /= Void
    must_save: file_data.data_changed
  local
    key_str, value_str : STRING
  do
    merge_data( d )
    -- The Case of the Disappearing File
    -- The current working folder may have changed. If so, go look for it again via
    -- the function hall_of_fame_folder.
    create file.make( hall_of_fame_folder + file_name )
    file.open_write
    file.put_string( in_file_warning_mess )
    from d.start until d.exhausted loop
      key_str := d.current_key
      file.put_string( "%N[" + key_str + "]" )
      value_str := d.current_value.out
      file.put_string( value_str )
      check_sum := calculate_check_sum( key_str + value_str )
      file.put_string( "%N{" + check_sum.out + "}" )
      d.forth
    end
    file.close
  ensure
    file_is_closed: file.is_closed
  end

end -- HALL_OF_FAME_FILE class