//*********************************************************************
//
//  NAV_UPGRADE.CMD - Command script to upgrade POI Data
//
//*********************************************************************

//! @li 2015/07/01 K.KOUEKA : EVO #7471 Dev
//! @li 2007/10/15 Evo 3794 - Extend country list
//! @li 2007/05/11 B. DAVID EVO #3293 : POI upgrade

/*** UPGRADE FLAGS ***/



/*** GLOBAL DEFINES ****/



// Script Types
typedef int  STATUS;
typedef void DIR;
typedef int  BOOL;
typedef int  size_t;
typedef void FILE;
#define TRUE     (1)
#define FALSE    (0)
#define OK       (0)
#define ERROR    (-1)
#define NULL     (void*) 0
#define O_RDWR   (2)

// Constants
#define MAX_DRIVE_NAME_LENGTH 10
#define MAX_FILENAME_LENGTH   50
#define MAX_PATH_LENGTH       100
#define MAX_INF_LINE_LENGTH   100
#define MAX_QUESTION_LENGTH   100

#define MAX_COUNTRY_NAME_HDD  30
#define MAX_DATA_PROVIDER     20
#define MAX_DATE_LENGTH       20
#define STRING_CONTINENT_ID   "CONTINENT_ID:"
#define STRING_CONTINENT_NAME "CONTINENT_NAME:"
#define STRING_CD_NAME        "CD_NAME:"
#define STRING_POI_PROVIDER   "POI_PROVIDER:"
#define STRING_DATA_POI       "DATA_POI:"
#define ALL_FILES             "*"
#define MAPPE_PATH            "/MAPPE/POI_USER"
#define POI_SOURCE_PATH       "POI_USER/"
#define POI_TARGET_PATH       "POI_USER/TEMP_"
#define POI_VER_FILE          "/TEMP_"
#define UPG_DATA_DIR          "DATA/"
#define UPG_BASE1_DIR         "BASE1/"

// Drive letters
#define DRIVE_CDROM "/D"
#define DRIVE_HDD   "/C"
#define DRIVE_NAV   "/H"
#define DRIVE_TFFS  "/F"
#define DRIVE_USB   "/bd0"

// Key Files
#define KEY_FILE_POI            "POI_VER.POI"
#define KEY_ZAR_FILE_POI        "ZAR_POI.BIN"

/*** SOFTWARE UPGRADE DEFINES ***/
// Continents
typedef enum
{
  UNKNOWN_CONTINENT = 0,
  EUROPE,            // 1
  AUSTRALIA,         // 2 WEST_AUSTRALIA, EAST_AUSTRALIA
  NORTH_AMERICA,     // 3 CONTINENTAL USA + CANADA
  SOUTH_AMERICA,     // 4 BRASILE, ARGENTINA, MESSICO
  INDIA,             // 5
  CHINA,             // 6
  MIDDLE_EAST,       // 7 EMIRATI ARABI, OMAN, QUWAIT, ...  PROBABILE EGITTO E ISRAELE
  FAR_EAST,          // 8 MACAO, HONG KONG, ....
  SOUTH_AFRICA,      // 9 SUD AFRICA
  NORTH_AFRICA       // 10 NORD AFRICA
} t_continent;


typedef struct
{
  t_continent m_continent;
  char m_continent_name[MAX_COUNTRY_NAME_HDD];
  char m_cd_name[MAX_COUNTRY_NAME_HDD];
  char m_poi_provider[MAX_DATA_PROVIDER];
  char m_date[MAX_DATE_LENGTH];
}t_poi_content;

typedef struct
{
  char  m_pFileName[MAX_PATH_LENGTH];
  char  m_pTargetPath[MAX_PATH_LENGTH];
  int   m_iSize;
} t_NavUpgData;


/*** EXTERN FUNCTION DECLARATIONS ***/

// File operations
int logMsg (char*,int,int,int,int,int,int);
int UPGSearchFile(char *Filename, char *RootDir, char *Param, char *TableDir );
STATUS UPGGetSearchResult(int index , char *SearchResult );
STATUS GetFileSize(char *file, int *size);
char* fgets(char * buf, size_t n, FILE * fp);
FILE* fopen(char * file, char * mode );
int fclose(FILE * fp);
int feof(FILE * fp);
STATUS UPGCopy(char* source, char* destination, int cut);
STATUS SpawnCopy(char* source, char* destination, int cut);

// String operations
STATUS strcpy (char* target, char* source);
STATUS strcat (char* target, char* source);
int strcmp (char* str1, char* str2);
int strncmp (char* str1, char* str2, int n);
STATUS strlen (char* str);
char* strstr(char* str, char* substr);


// MMI UPG Panel management
STATUS ClearScreen(void);
STATUS ShowNavigationBargraph(void);
STATUS StepBargraph(char *text, int index);
STATUS ShowCDVerification(void);
STATUS ShowCDIdentification(void);
STATUS ShowCDProblem(void);
STATUS ShowNavigationQuestionScreen(char *text, int *answer);

// Others
unsigned long tickGet (void);
STATUS taskDelay (int ticks);
void *malloc(size_t nBytes);
void *realloc(void *pBlock, size_t newSize );
void free(void * ptr);
int atoi(char * p_str);

STATUS UPGCDEject(void);
int IsUpgCheatCodeActivated(void);
STATUS SendMessageMMINavPOILoaded(void);
STATUS        CheckCRCFile( const char* p_file_name );

STATUS CompareToDBContinent(int p_cd_continent);
STATUS        InstalPOIs(char* p_path, char* p_bargraph_name);


/*** INTERN FUNCTION DECLARATION ***/
STATUS  ComputePOITargetPath (char* p_file_name,
                            char* p_source_drive,
                            char* p_target_drive,
                            char* p_target_name);

STATUS ReplaceInPath(char *p_pPath, char *p_pStringToReplace, char *p_pStringToReplaceWhith );

STATUS ExtractPOIInfo(const char* p_filepath, t_poi_content* p_content);


/****************************** MAIN ******************************/

int main(int argc, char **argv)
{
  // Local variables for general purpose
  STATUS l_script_status = OK;
  char l_source_drive[MAX_DRIVE_NAME_LENGTH];
  char l_target_drive[MAX_DRIVE_NAME_LENGTH];

  int  l_i=0;
  int  l_j=0;

  char l_path[MAX_PATH_LENGTH];
  char l_path_to_send [MAX_PATH_LENGTH];
  char l_key_file_name[MAX_FILENAME_LENGTH];

  int l_bUpgRequired = FALSE;
  int l_bUpgCheatCodeON = FALSE;
  char l_pQuestionText[MAX_QUESTION_LENGTH];

  t_NavUpgData *l_poi_file_list = NULL;
  unsigned int l_poi_file_number = 0;
  char l_search_result[MAX_PATH_LENGTH];
  unsigned long l_lTotalSize = 0;
  unsigned long l_lCompletedSize = 0;
  int l_iPercentage = 0;
  FILE* l_file            = NULL;


  t_poi_content l_poi_content;
  l_poi_content.m_continent = UNKNOWN_CONTINENT;
  l_poi_content.m_continent_name[0] = '\0';
  l_poi_content.m_cd_name[0] = '\0';
  l_poi_content.m_poi_provider[0] = '\0';
  l_poi_content.m_date[0] = '\0';

  /*** SCRIPT INITIALIZATION ***/

  logMsg("Script initialization +, Time = %ld\n",tickGet(),0,0,0,0,0);

  //Get current source drive
  if(argc != 3)
  {
    logMsg("Incorrect number of params\n",0,0,0,0,0,0);
    l_script_status = ERROR;
    ShowCDProblem();
  }
  else
  {
    strcpy(l_source_drive,argv[1]);
    logMsg("Source drive is %s\n",l_source_drive,0,0,0,0,0);

    //Get key file
    strcpy ( l_key_file_name, argv[2] );
    if(0 != strcmp(l_key_file_name,KEY_FILE_POI))
    {
      logMsg ( "INVALID ARGUMENT : l_key_file_name is %s\n",l_key_file_name,0,0,0,0,0 );
      l_script_status = ERROR;
      ShowCDProblem();
    }
  }

  //Get current target drive "/H"
  strcpy ( l_target_drive, DRIVE_NAV );

  if(OK == l_script_status)
  {
    logMsg("Target drive is %s\n",l_target_drive,0,0,0,0,0);
    logMsg("Source key file is %s\n",l_key_file_name,0,0,0,0,0 );
  }

  logMsg("Script initialization -, Time = %ld\n",tickGet(),0,0,0,0,0);


  /*** VERSION CHECK ***/

  if ( OK == l_script_status )
  {
    logMsg("Version check +, Time = %ld\n",tickGet(),0,0,0,0,0);

    ShowCDIdentification();
    taskDelay(100);
    strcpy ( l_path, l_source_drive);
    strcat ( l_path, "/" );
    strcat ( l_path, l_key_file_name);

    // Read the information file
    if(OK == ExtractPOIInfo(l_path, &l_poi_content))
    {
      if(ERROR == CompareToDBContinent((int)l_poi_content.m_continent))
      {
        logMsg ( "CompareToDBContinent failed continent : %d\n",
                  l_poi_content.m_continent,0,0,0,0,0 );
        l_script_status = ERROR;
      }
      else
      {
        logMsg ( "CompareToDBContinent OK\n",0,0,0,0,0,0 );
      }
    }
    else
    {
      logMsg ( "ExtractPOIInfo error on %s\n",l_path,0,0,0,0,0 );
      l_script_status = ERROR;
      ShowCDProblem();
    }
  }

  //If no exception detected check if compressed file is present
  if (ERROR != l_script_status)
  {
    strcpy ( l_path, l_source_drive);
    strcat ( l_path, "/" );
    strcat ( l_path, UPG_DATA_DIR );
    strcat ( l_path, UPG_BASE1_DIR );
    strcat ( l_path, KEY_ZAR_FILE_POI);
    logMsg ( "Path Tested (%s) \n", (int)l_path, 0, 0, 0, 0, 0 );

    l_file = fopen ( (char*)l_path,"r");
    if (NULL == l_file)
    {
      logMsg ( "[ERROR] Missing compressed file \n", 0,0,0,0,0,0 );
      l_script_status = ERROR;
      ShowCDProblem();
    }
    else
    {
      l_poi_file_number = 1;
      logMsg ( "Compressed file is present. Ask user what he wants \n", 0,0,0,0,0,0 );
      fclose(l_file);
    }

  }

  /*** SCRIPT CHECK CRC ***/
  if (ERROR != l_script_status)
  {
    if(ERROR == CheckCRCFile(l_path))
    {
      logMsg ( "CheckCRCFile (%s) Error!!!\n", (int)l_path, 0, 0, 0, 0, 0 );
      l_script_status = ERROR;
    }
    else
    {
      strcpy (l_path_to_send , l_path);
      logMsg ( "CheckCRCFile (%s) OK!!!\n", (int)l_path, 0, 0, 0, 0, 0 );
    }
  }


  /*** ASK USER AGREEMENT ***/

  if ( ERROR != l_script_status )
  {
    strcpy ( l_pQuestionText, l_poi_content.m_cd_name);
    strcat ( l_pQuestionText, " " );
    strcat ( l_pQuestionText, l_poi_content.m_date);

    //Do not ask user agreement if drive is empty
    ShowNavigationQuestionScreen ( l_pQuestionText, &l_bUpgRequired );

    if ( FALSE == l_bUpgRequired )
    {
      logMsg ( "UPGRADE CANCELED BY USER!\n",0,0,0,0,0,0 );
    }
  }

  /*** UPGRADE ***/

  logMsg("Upgrade +, Time = %ld\n",tickGet(),0,0,0,0,0);

  if ( ( OK == l_script_status ) && ( TRUE == l_bUpgRequired ) )
  {
    ShowNavigationBargraph();
    StepBargraph (l_pQuestionText, 0);
    taskDelay(100);

    for ( l_j=0; l_j<3; l_j++ )
    {
      if ( ERROR == InstalPOIs(l_path_to_send, l_pQuestionText))
      {
        logMsg("InstalPOIs error (%s)\n",(int)l_path_to_send,0,0,0,0,0);
        l_script_status = ERROR;
      }
      else
      {
        break;
      }
    }

    //Copy failed
    if ( 3 == l_j )
    {
      l_script_status = ERROR;
      ShowCDProblem();
    }

    if(OK == l_script_status)
    {
      char l_destination[MAX_PATH_LENGTH];
      strcpy ( l_path, l_source_drive);
      strcat ( l_path, "/" );
      strcat ( l_path, l_key_file_name);
      strcpy ( l_destination, l_target_drive);
      strcat ( l_destination, POI_VER_FILE );
      strcat ( l_destination, l_key_file_name);

      if(ERROR == UPGCopy(l_path,l_destination,0))
      {
        logMsg("UPGCopy error %s -> %s \n",(int)l_path,(int)l_destination,0,0,0,0);
        l_script_status = ERROR;
      }
    }

  }

  logMsg("Upgrade -, Time = %ld\n",tickGet(),0,0,0,0,0);

  if ( NULL != l_poi_file_list)
  {
    free(l_poi_file_list);
    l_poi_file_list = NULL;
  }

  /*** TERMINATION ***/

  //if APC is OFF do not eject the CD or disk formatted
  if ( ( FALSE == l_bUpgCheatCodeON ) &&
       ( TRUE == IsUpgCheatCodeActivated()) )
  {

  }
  else
  {
    if ( !strcmp(l_source_drive,DRIVE_CDROM) )
    {
      if ( ERROR == UPGCDEject() )
      {
        logMsg ( "UPG Media Eject error\n",0,0,0,0,0,0 );
      }
    }
  }

  if ( (OK == l_script_status) && ( TRUE == l_bUpgRequired ))
  {
    if(ERROR == SendMessageMMINavPOILoaded())
    {
      logMsg ( "SendMessageMMINavPOILoaded failed\n",0,0,0,0,0,0 );
      l_script_status = ERROR;
    }
  }

  if ( OK == l_script_status)
  {
    logMsg("UPGRADE COMPLETE!\n",0,0,0,0,0,0);
  }
  else
  {
    logMsg("SCRIPT ERROR!\n",0,0,0,0,0,0);
  }

  ClearScreen();
  taskDelay(100);

  return ( l_script_status );
}


/********************** INTERN FUNCTION DEFINITION **********************/

STATUS  ComputePOITargetPath (char* p_file_name,
                            char* p_source_drive,
                            char* p_target_drive,
                            char* p_target_name)
{
  STATUS l_status = OK;
  char l_temp_name[MAX_PATH_LENGTH];

  strcpy(l_temp_name,p_file_name);

  if(OK == ReplaceInPath(l_temp_name,p_source_drive,p_target_drive))
  {
    if(OK == ReplaceInPath(l_temp_name,POI_SOURCE_PATH,POI_TARGET_PATH))
    {
      strcpy(p_target_name,l_temp_name);
    }
    else
    {
      logMsg ( "ReplaceInPath POI_USER by TEMP_POI_USER failed on %s \n",
                (char*)l_temp_name,0,0,0,0,0 );
      l_status = ERROR;
    }
  }
  else
  {
    logMsg ( "ReplaceInPath %s by %s failed on %s \n",
              (char*)p_source_drive,
              (char*)p_target_drive,
              (char*)l_temp_name,0,0,0);
    l_status = ERROR;
  }
  return ( l_status );
}


STATUS ReplaceInPath(char *p_pPath, char *p_pStringToReplace, char *p_pStringToReplaceWhith )
{
  int l_iLenPath = 0;
  int l_iLenStrToReplace = 0;
  int l_iLenStrToReplaceWith = 0;

  char *l_pPrefPtr = NULL;
  char *l_pPostPtr = NULL;
  char l_pPath[MAX_PATH_LENGTH];

  char l_pPostString[MAX_PATH_LENGTH];


  //Check parameters
  if ( ( NULL == p_pPath ) || ( NULL == p_pStringToReplace ) || ( NULL == p_pStringToReplaceWhith ) )
  {
    logMsg("ReplaceInPath: NULL param\n",0,0,0,0,0,0);
    return ( ERROR );
  }

  l_iLenPath = strlen(p_pPath);
  l_iLenStrToReplace = strlen(p_pStringToReplace);
  l_iLenStrToReplaceWith = strlen(p_pStringToReplaceWhith);

  //Check substring lengths
  if ( (l_iLenStrToReplace > l_iLenPath) || (l_iLenStrToReplaceWith > l_iLenPath) )
  {
    logMsg("ReplaceInPath: substring is longer than string\n",0,0,0,0,0,0);
    return ( ERROR );
  }

  //Local copy
  strcpy ( l_pPath, p_pPath );

  //Look for pref ptr
  l_pPrefPtr = strstr ( l_pPath, p_pStringToReplace );
  if ( NULL == l_pPrefPtr )
  {
    logMsg("ReplaceInPath: Cannot find substring\n",0,0,0,0,0,0);
    return ( ERROR );
  }

  //Look for post ptr
  l_pPostPtr = l_pPrefPtr + l_iLenStrToReplace;

  //Get post string
  strcpy ( l_pPostString, l_pPostPtr );

  //Replace substring
  strcpy ( l_pPrefPtr, p_pStringToReplaceWhith );

  //Append post string
  strcat ( l_pPath, l_pPostString );

  //Copy back
  strcpy ( p_pPath, l_pPath );

  return ( OK );
}



STATUS ExtractPOIInfo(const char* p_filepath, t_poi_content* p_content)
{
  STATUS l_status = OK;
  FILE* l_file = NULL;
  char l_data[MAX_INF_LINE_LENGTH];
  if(NULL == p_filepath || NULL == p_content)
  {
    logMsg("ExtractPOIInfo: bad parameter\n",0,0,0,0,0,0);
    return (ERROR);
  }
  l_file = fopen((char*)p_filepath,"r");
  if(NULL != l_file)
  {
    char* l_ptr_data = NULL;

    if(NULL != fgets(l_data,MAX_INF_LINE_LENGTH,l_file))
    {
      l_ptr_data = strstr(l_data,STRING_CONTINENT_ID);
      if(NULL != l_ptr_data)
      {
        p_content->m_continent = (t_continent)atoi(l_ptr_data +
                                                    strlen(STRING_CONTINENT_ID));
      }
      else
      {
        logMsg("ExtractPOIInfo: Can't find CONTINENT_ID:\n",0,0,0,0,0,0);
        l_status = ERROR;
      }
    }
    else
    {
      logMsg("ExtractPOIInfo: fgets failed\n",0,0,0,0,0,0);
      l_status = ERROR;
    }

    if(NULL != l_ptr_data
        && NULL != fgets(l_data,MAX_INF_LINE_LENGTH,l_file))
    {
      l_ptr_data = strstr(l_data,STRING_CONTINENT_NAME);
      if(NULL != l_ptr_data)
      {
        strcpy(p_content->m_continent_name,
                l_ptr_data + strlen(STRING_CONTINENT_NAME));
        p_content->m_continent_name[MAX_COUNTRY_NAME_HDD-1]='\0';
      }
      else
      {
        logMsg("ExtractPOIInfo: Can't find CONTINENT_NAME:\n",0,0,0,0,0,0);
        l_status = ERROR;
      }
    }
    else
    {
      logMsg("ExtractPOIInfo: fgets failed\n",0,0,0,0,0,0);
      l_status = ERROR;
    }

    if(NULL != l_ptr_data
        && NULL != fgets(l_data,MAX_INF_LINE_LENGTH,l_file))
    {
      l_ptr_data = strstr(l_data,STRING_CD_NAME);
      if(NULL != l_ptr_data)
      {
        strcpy(p_content->m_cd_name,
                l_ptr_data + strlen(STRING_CD_NAME));
        p_content->m_cd_name[MAX_COUNTRY_NAME_HDD-1]='\0';
      }
      else
      {
        logMsg("ExtractPOIInfo: Can't find CD_NAME:\n",0,0,0,0,0,0);
        l_status = ERROR;
      }
    }
    else
    {
      logMsg("ExtractPOIInfo: fgets failed\n",0,0,0,0,0,0);
      l_status = ERROR;
    }

    if(NULL != l_ptr_data
        && NULL != fgets(l_data,MAX_INF_LINE_LENGTH,l_file))
    {
      l_ptr_data = strstr(l_data,STRING_POI_PROVIDER);
      if(NULL != l_ptr_data)
      {
        strcpy(p_content->m_poi_provider,
                l_ptr_data + strlen(STRING_POI_PROVIDER));
        p_content->m_poi_provider[MAX_DATA_PROVIDER-1]='\0';
      }
      else
      {
        logMsg("ExtractPOIInfo: Can't find POI_PROVIDER:\n",0,0,0,0,0,0);
        l_status = ERROR;
      }
    }
    else
    {
      logMsg("ExtractPOIInfo: fgets failed\n",0,0,0,0,0,0);
      l_status = ERROR;
    }

    if(NULL != l_ptr_data
        && NULL != fgets(l_data,MAX_INF_LINE_LENGTH,l_file))
    {
      l_ptr_data = strstr(l_data,STRING_DATA_POI);
      if(NULL != l_ptr_data)
      {
        strcpy(p_content->m_date,
                l_ptr_data + strlen(STRING_DATA_POI));
        p_content->m_date[MAX_DATE_LENGTH-1]='\0';
      }
      else
      {
        logMsg("ExtractPOIInfo: Can't find DATA_POI:\n",0,0,0,0,0,0);
        l_status = ERROR;
      }
    }
    else
    {
      logMsg("ExtractPOIInfo: fgets failed\n",0,0,0,0,0,0);
      l_status = ERROR;
    }

    fclose(l_file);
  }
  else
  {
    logMsg("ExtractPOIInfo: Can't open %s file\n",(int)p_filepath,0,0,0,0,0);
    l_status = ERROR;
  }

  return (l_status);
}

