/* Copyright Statement:
 *
 * This software/firmware and related documentation ("MediaTek Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
 * the prior written permission of MediaTek inc. and/or its licensors, any
 * reproduction, modification, use or disclosure of MediaTek Software, and
 * information contained herein, in whole or in part, shall be strictly
 * prohibited.
 *
 * Copyright  (C) [2020]  MediaTek Inc. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
 * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
 * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
 * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
 * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
 *
 * The following software/firmware and/or related documentation ("MediaTek
 * Software") have been modified by MediaTek Inc. All revisions are subject to
 * any receiver's applicable license agreements with MediaTek Inc.
 */

#include <common.h>
#include <command.h>
#include <cmdtable.h>
#include <debug_impl.h>
#include <utility.h>
#include <system_impl.h>
#include <upgrade_utility.h>
#include "generated/version_autogenerated.h"
#include <boot_impl.h>
#include <timestamp.h>
#ifdef CONFIG_STOP_TO_CONSOLE
#include <environment.h>
#endif



//-------------------------------------------------------------------------------------------------
//  Local Defines
//-------------------------------------------------------------------------------------------------
#define SCRIPT_BUF_FOR_DO_MSTAR 4096
#define ARG_NUM_SCRIPT_FILE         1
#define IS_ARG_AVAILABLE_SCRIPT_FILE(x) ((x) > ARG_NUM_SCRIPT_FILE)
#define DEFAULT_SCRIPT_FILE_NAME    "auto_update.txt"   // script file name
#define ARG_SCRIPT_FILE(x)              (x)[ARG_NUM_SCRIPT_FILE]
#ifdef CONFIG_STOP_TO_CONSOLE

#define ENV_BOOTDELAY                   "bootdelay"
#endif


int do_scriptstar (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    char* buffer = NULL;
    char cmd_buffer[CMD_BUF] = {0};
    char *script_buf = NULL;
    char *next_line = NULL;
    char *ScriptFile = NULL;
    unsigned long iFilesize = 0;
    char *tmp = NULL;
    int BeAbort = 1;
    int snprintf_len;

    UBOOT_TRACE("IN\n");

    ScriptFile= IS_ARG_AVAILABLE_SCRIPT_FILE(argc) ? ARG_SCRIPT_FILE(argv) : DEFAULT_SCRIPT_FILE_NAME;
    UBOOT_DEBUG("ScriptFile=%s\n",ScriptFile);

    buffer=(char *)malloc(SCRIPT_BUF_FOR_DO_MSTAR);
    if (buffer == NULL)
    {
        UBOOT_ERROR("ERROR: Failed to allocate 0x%x bytes.\n",SCRIPT_BUF_FOR_DO_MSTAR);
        return -1;
    }
    // Set mstar commmand abort or not when cmd error.
    tmp = env_get ("CmdAbort");
    if (tmp != NULL)
    {
        BeAbort = (int)simple_strtol(tmp, NULL, 10);
        UBOOT_DEBUG("BeAbort=%d\n",BeAbort);
    }

    // Load script
    memset(buffer, 0 , SCRIPT_BUF_FOR_DO_MSTAR);
    memset(cmd_buffer, 0 , CMD_BUF);
    snprintf_len = snprintf(cmd_buffer, CMD_BUF, "tftp %p %s", buffer,ScriptFile);
    if (snprintf_len >= CMD_BUF)
    {
        UBOOT_ERROR("The array size is too small(%d), snprintf fail '%s'\n", CMD_BUF, cmd_buffer);
        free(buffer);
        return -1;
    }
    UBOOT_DEBUG("cmd=%s\n",cmd_buffer);
    if(0 != run_command(cmd_buffer, 0))
    {
        UBOOT_ERROR("cmd: %s\n",cmd_buffer);
        free(buffer);
        return -1;
    }


    // Run script
    iFilesize = (unsigned long)simple_strtol(env_get("filesize"), NULL, 16);
    UBOOT_DEBUG("iFilesize=0x%lx\n",iFilesize);
    script_buf = buffer;
    script_buf[iFilesize]='\n'; script_buf[iFilesize+1]='%';
    while ((next_line = get_script_next_line(&script_buf)) != NULL)
    {
        next_line = para_replace(next_line, (argc-2), &argv[1]);
        UBOOT_INFO ("\n>> %s \n", next_line);
        if(0 != run_command(next_line, 0))
        {
            UBOOT_ERROR("command error!\n");
            if(BeAbort == 1)
            {
                free(buffer);
                return -1;
            }
        }
    }
    free(buffer);
    UBOOT_TRACE("OK\n");
    return 0;
}

U_BOOT_CMD(
    scriptstar ,    2,    0,     do_scriptstar,
    "update kernal & root file system automatically by script file",
    "scriptstar [script_file_name]\n"
    "set CmdAbort = 0 in env to ignore the abort when cmd error\n"
);

int do_del_boogargs (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
   int ret;
   UBOOT_TRACE("IN\n");
   if(argc!=2)
   {
        return cmd_usage(cmdtp);
   }

   ret = del_bootargs(argv[1],1);
   if(ret==0)
   {
        UBOOT_TRACE("OK\n");
   }
   else
   {
        UBOOT_ERROR("delete %s fail\n",argv[1]);
   }
   return ret;
}


U_BOOT_CMD(
    deletebootargs, 2, 0, do_del_boogargs,
    "delete the specific cofig that is in the bootargs\n",
    "[config]\n"
    "For example: deleteBootargs autotest\n"
);

int do_add_bootargs (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
   int ret;
   unsigned int prefixLen=0;
   unsigned int contentLen=0;
   char *buffer=NULL;
   int snprintf_len;
   UBOOT_TRACE("IN\n");
   if(argc!=3)
   {
        return cmd_usage(cmdtp);
   }
   prefixLen=strlen(argv[1]);
   contentLen=strlen(argv[2]);
   //2? for '=' and the end symbol
   #define BUFFER_SIZE (prefixLen+contentLen+2)
   buffer=malloc(BUFFER_SIZE);
   if(buffer==NULL)
   {
       UBOOT_ERROR("malloc fail\n");
       return -1;
   }
   printf(" argv[1]%s \n",argv[1]);
   printf(" argv[2]%s \n",argv[2]);
   snprintf_len = snprintf(buffer,BUFFER_SIZE,"%s=%s",argv[1],argv[2]);
   if (snprintf_len >= BUFFER_SIZE)
   {
       UBOOT_ERROR("The array size is too small(%d), snprintf fail '%s'\n", BUFFER_SIZE, buffer);
       free(buffer);
       return -1;
   }
   UBOOT_DEBUG("buffer: %s\n",buffer);
   ret = add_bootargs(argv[1],buffer,1);
   if(ret==0)
   {
        UBOOT_TRACE("OK\n");
   }
   else
   {
        UBOOT_ERROR("delete %s fail\n",argv[1]);
   }
   free(buffer);
   #undef BUFFER_SIZE
   return ret;
}

U_BOOT_CMD(
    addbootargs, 3, 0, do_add_bootargs,
    "set a new config to the bootargs\n",
    "[config][content]\n"
    "For example: addBootargs autotest true\n"
);

int do_add_version2bootargs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
   int ret=0;
   char cmd_buffer[256] = {0};
   char date_buffer[32] = {0};
   int snprintf_len;
   memset(cmd_buffer, 0 , 256);
   snprintf_len = snprintf(cmd_buffer, 256, "addbootargs androidboot.loaderversion %s", U_BOOT_VERSION);
   if (snprintf_len >= 256)
   {
       UBOOT_ERROR("The array size is too small(%d), snprintf fail '%s'\n", 256, cmd_buffer);
       return -1;
   }
   strcat (cmd_buffer, "+");
   snprintf(date_buffer, 256, "%s", U_BOOT_DATE);

   for(int index = 0;index < strlen(date_buffer);index++)
   {
   		if(date_buffer[index] == ' ')
		{
			date_buffer[index] = '-';
		}
   	
   }
   printf("date_buffer=%s\n",date_buffer);
   strcat (cmd_buffer, date_buffer);
   strcat (cmd_buffer, "+");
   strcat (cmd_buffer, U_BOOT_TIME);
   printf("cmd=%s\n",cmd_buffer);
   if(0 != run_command(cmd_buffer, 0))
   {
       UBOOT_ERROR("cmd: %s\n",cmd_buffer);
       ret= -1;
   }

   return ret;
}

U_BOOT_CMD(
    addversion, 1, 0, do_add_version2bootargs,
    "set a uboot version to the bootargs\n",
    " \n"
    "For example: addVersion \n"
);


int do_add_retry_count(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
   int ret=0;
   sys_add_retry_count();
   return ret;
}

U_BOOT_CMD(
    retrycount, 1, 0, do_add_retry_count,
    "set retry count +1\n",
    " \n"
    "For example: retrycount \n"
);

int do_show_retry_count(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
   int ret=0;
   sys_show_retry_count();
   return ret;
}

U_BOOT_CMD(
    showretrycount, 1, 0, do_show_retry_count,
    "showretrycount\n",
    " \n"
    "For example: showretrycount \n"
);

int do_set_retry_count(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    int ret=0;
    unsigned int retry_count = 0;

    if (argc != 2)
    {
        return CMD_RET_USAGE;
    }
    retry_count = simple_strtoul(argv[1], NULL, 10);
    if(retry_count>3)
    {
        return CMD_RET_USAGE;
    }
    sys_set_retry_count(retry_count);
    return ret;
}

U_BOOT_CMD(
    setretrycount, CONFIG_SYS_MAXARGS, 0, do_set_retry_count,
    "setretrycount\n",
    " \n"
    "For example: setretrycount # 0~3 \n"
);


int do_boot_device_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{

    char device_name[STORAGE_DEVICE_BUF_SIZE] = {0};
    if(sys_get_boot_device(device_name, sizeof(device_name))==-1)
    {
        UBOOT_ERROR("[ERROR] Get boot device fail !! \n");
        return CMD_RET_FAILURE;
    }
    UBOOT_DEBUG("device %s \n",device_name);
    if(strncmp(device_name, "usb", strlen("usb")) == 0)
    {
        run_command("usb start",0);
    }
    return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
    bootdeviceusb, 1, 0, do_boot_device_usb,
    "check boot device if is USB ,init usb HW\n",
    " \n"
    "For example: bootdeviceusb \n"
);
int do_force_boot_recovery(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    int ret;
    ret = is_recovery_mode();
    if(ret == 1)
    {
        printf("#### boot to recovery  !!\n");
        return run_command(env_get("recoverycmd"), 0);
    }

    return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
    forcebootrecovery, 1, 0, do_force_boot_recovery,
    "force boot to recovery mode\n",
    " \n"
    "For example: forcebootrecovery \n"
);

int do_format_env(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    if (argc != 3)
		return CMD_RET_USAGE;

    UBOOT_DEBUG("Start to format %s %s env\n", argv[1], argv[2]);

    if(format_uenv_to_ext4(argv[1], argv[2]) != CMD_RET_SUCCESS)
	{
		UBOOT_ERROR("[ERROR] Convert 8MB uenv partition to EXT4 format fail!\n");
		return CMD_RET_FAILURE;
	}

    return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
    formatenv, CONFIG_SYS_MAXARGS, 0, do_format_env,
    "clean all uboot environment in 'uenv' partition & convert to EXT4 format.\n",
    "<interface> <dev>\n"
    "For example: formatenv mmc 0\n"
);

int do_set_recovery(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    if(argc != 1)
        return CMD_RET_USAGE;

    UBOOT_DEBUG("Start to set recovery flag in misc partition\n");

    if(set_recovery() != 0)
    {
        UBOOT_ERROR("[ERROR] Set recovery flag in misc partition fail!\n");
        return CMD_RET_FAILURE;
    }

    UBOOT_DEBUG("Set recovery flag in misc partition success\n");

    return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
    setrecovery, CONFIG_SYS_MAXARGS, 0, do_set_recovery,
    "Set recovery flag in misc partition\n",
    "For example: setrecovery\n"
);

int do_wipe_userdata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    if (argc != 1)
        return CMD_RET_USAGE;

    UBOOT_DEBUG("Start to wipe userdata flag in misc partition\n");

    if (wipe_user_data() != 0)
    {
        UBOOT_ERROR("[ERROR] Wipe userdata flag in misc partition fail!\n");
        return CMD_RET_FAILURE;
    }

    UBOOT_DEBUG("Wipe userdata flag in misc partition success\n");

    return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
    wipeuserdata, CONFIG_SYS_MAXARGS, 0, do_wipe_userdata,
    "Wipe userdata flag in misc partition\n",
    "\nafter reset, userdata partition will be formated during recovery mode.\n"
    "For example: wipeuserdata\n"
);

int do_wipe_userdata_in_uboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    if (argc != 1)
        return CMD_RET_USAGE;

    UBOOT_DEBUG("Start to wipe userdata and metadata partition\n");

    if (wipe_user_data_in_uboot() != 0)
    {
        UBOOT_ERROR("[ERROR] Wipe userdata and metadata partition fail!\n");
        return CMD_RET_FAILURE;
    }

    UBOOT_DEBUG("Wipe userdata and metadata partition success\n");

    return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
    wipeuserdataboot, CONFIG_SYS_MAXARGS, 0, do_wipe_userdata_in_uboot,
    "Wipe userdata flag in misc partition\n",
    "\nafter reset, userdata partition will be formated during recovery mode.\n"
    "For example: wipeuserdata\n"
);

#ifdef CONFIG_STOP_TO_CONSOLE

int do_reset_bootdelay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    if (argc != 1)
        return CMD_RET_USAGE;

    UBOOT_DEBUG("Start to set bootdelay\n");
    env_set(ENV_BOOTDELAY, "-1");
    env_save();


    UBOOT_DEBUG("set bootdelay success\n");

    return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
    reset_bootdelay, CONFIG_SYS_MAXARGS, 0, do_reset_bootdelay,
    "set bootdelay to -1 to stop mboot to console\n",
    "\nFor rollback index reset we need stop to console.\n"
    "For example: reset_bootdelay\n"
);

#endif
