/*
*********************************************************************************************************
* Temporarily set the used CIK to something else
* or reset it to value stored in flash by calling with NULL
*********************************************************************************************************
*/
void Exosite_UseCIK(CPU_CHAR * pCIK)
{
    if (NULL != pCIK && 0 != *pCIK)
    {
        Str_Copy_N(CIK, pCIK, CIK_LENGTH);
    }
    else
    {
        rdk_meta *meta_info = (rdk_meta *)RDK_META_LOCATION;
        Str_Copy_N(CIK, (CPU_CHAR*)meta_info->cik, CIK_LENGTH);
    }
}
/*
*********************************************************************************************************
* Store new CIK in flash
*********************************************************************************************************
*/
void Exosite_SetCIK(CPU_CHAR * pCIK)
{
    rdk_meta *meta_info = (rdk_meta *)RDK_META_LOCATION;

    if (0 != Str_Cmp_N((CPU_CHAR*)meta_info->cik, pCIK, CIK_LENGTH))
    {
        rdk_meta_write((unsigned char *)pCIK, CIK_LENGTH, (unsigned char *)meta_info->cik);
    }
    Str_Copy_N(CIK, pCIK, CIK_LENGTH);
}
CPU_BOOLEAN Exosite_Init(CPU_CHAR * pVen, CPU_CHAR * pOS, CPU_CHAR * pVer, NET_IF_NBR if_nbr)
{
    init_mac_address(if_nbr);
    init_flash_content();

    Str_Copy_N(VEN, pVen, VEN_SIZE);
    VEN[VEN_SIZE - 1] = 0;
    VEN_LENGTH = Str_Len(VEN);
    
    Str_Copy_N(OSN, pOS, OSN_SIZE);
    OSN[OSN_SIZE - 1] = 0;
    OSN_LENGTH = Str_Len(OSN);

    Str_Copy_N(OSV, pVer, OSV_SIZE);
    OSV[OSV_SIZE - 1] = 0;
    OSV_LENGTH = Str_Len(OSV);

    return Exosite_Reinit();
}
CPU_CHAR  *HTTP_Dict_ValCopy (const  HTTP_DICT   *p_dict_tbl,
                                     CPU_INT32U   dict_size,
                                     CPU_INT32U   key,
                                     CPU_CHAR    *p_buf,
                                     CPU_SIZE_T   buf_len)
{
    const  HTTP_DICT  *p_entry;
           CPU_CHAR   *p_str_rtn;


    p_entry = &p_dict_tbl[key];
    if (p_entry->Key != key) {                                  /* If entry key doesn't match dictionary key ...        */
        p_entry = HTTP_Dict_EntryGet(p_dict_tbl,                /* ... get first entry that match the    key.           */
                                     dict_size,
                                     key);
        if (p_entry == DEF_NULL) {
            return ((CPU_CHAR *)0);
        }
    }


    if ((p_entry->StrLen == 0u)       ||                        /* Validate entry value.                                */
        (p_entry->StrPtr == DEF_NULL)) {
         return ((CPU_CHAR *)0);
    }

    if (p_entry->StrLen > buf_len) {                            /* Validate value len and buf len.                      */
        return ((CPU_CHAR *)0);
    }


   (void)Str_Copy_N(p_buf, p_entry->StrPtr, p_entry->StrLen);   /* Copy string to the buffer.                           */

    p_str_rtn = p_buf + p_entry->StrLen;                        /* Set ptr to return.                                   */

    return (p_str_rtn);
}
static void init_flash_content(void)
{
    rdk_meta *meta_info;

    rdk_meta_init();

    meta_info = (rdk_meta *)RDK_META_LOCATION;

    if (0 != Str_Cmp_N((CPU_CHAR*)meta_info->mark, EXOMARK, Str_Len(EXOMARK)))
    {
        rdk_meta_defaults();
    }

    // Get local copy as it can be set temporarily
    Str_Copy_N(CIK, (CPU_CHAR*)meta_info->cik, CIK_LENGTH);

    // Convert stored copy to something usable
    IP   =  meta_info->server[0] * 16777216
          + meta_info->server[1] * 65536
          + meta_info->server[2] * 256
          + meta_info->server[3] * 1;
    PORT =  meta_info->server[4] * 256
          + meta_info->server[5] * 1;
}
void update_m2ip(void)
{
    NET_SOCK_ID  sock;
    CPU_SIZE_T   len, rxlen, IPLEN = 23; // 23 => 3*6+5 => "nnn,nnn,nnn,nnn,nnn,nnn"
    CPU_CHAR    *p;
    CPU_CHAR     rx[RX_SIZE], ip[23];

    sock = socket_open();

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

    if (
        18 != socket_send(sock, "GET /ip HTTP/1.1\r\n", 18) ||
        22 != socket_send(sock, "Host: m2.exosite.com\r\n", 22) ||
        35 != socket_send(sock, "Accept: text/plain; charset=utf-8\r\n", 35) ||
        2  != socket_send(sock, "\r\n", 2)
    )
    {
        socket_close(sock);
        return;
    }

    // @HTTP/x.x NNN@
    rxlen = socket_recv(sock, rx, 12);

    if (12 == rxlen && '2' == rx[9] && '0' == rx[10] && '0' == rx[11])
    {
        CPU_CHAR crlf = 0;
        CPU_CHAR iplen = 0;

        do
        {
            rxlen = socket_recv(sock, rx, RX_SIZE);
            len = rxlen;
            p = rx;

            // Find 4 consecutive \r or \n - should be: \r\n\r\n
            while (0 < len && 4 > crlf)
            {
                if ('\r' == *p || '\n' == *p)
                {
                    ++crlf;
                }
                else
                {
                    crlf = 0;
                }
                ++p;
                --len;
            }

            // The body is "nnn,nnn,nnn,nnn,nnn,nnn"
            if (0 < len && 4 == crlf && IPLEN > iplen)
            {
                // TODO, be more robust - match Content-Length header value to IPLEN
                CPU_CHAR need, part;
                need = IPLEN - iplen;
                part = need < len ? need : len;
                Str_Copy_N(ip + iplen, p, part);
                iplen += part;
            }
        } while (RX_SIZE == rxlen);

        if (0 < iplen && IPLEN >= iplen)
        {
            CPU_CHAR server_ip[6];
            CPU_CHAR i;

            p = ip;

            for (i = 0; i < 6 || iplen > 0; i++)
            {
                if (*p >= '0' && *p <= '9')
                {
                    server_ip[i] = *p++ - '0';
                    if (0 == --iplen) break;
                }
                if (*p >= '0' && *p <= '9')
                {
                    server_ip[i] *= 10;
                    server_ip[i] += *p++ - '0';
                    if (0 == --iplen) break;
                }
                if (*p >= '0' && *p <= '9')
                {
                    server_ip[i] *= 10;
                    server_ip[i] += *p++ - '0';
                    --iplen;
                }
                if (iplen > 0)
                {
                    if (5 == i || ',' != *p++)
                    {
                        break;
                    }
                    --iplen;
                }
            }

            if (6 == i)
            {
                rdk_meta *meta_info = (rdk_meta *)RDK_META_LOCATION;

                if (0 != Str_Cmp_N((CPU_CHAR*)meta_info->server, server_ip, 6))
                {
                    rdk_meta_write((unsigned char *)server_ip, 6, (unsigned char *)meta_info->server);

                    // Convert stored copy to something usable
                    IP   =  server_ip[0] * 16777216
                          + server_ip[1] * 65536
                          + server_ip[2] * 256
                          + server_ip[3] * 1;
                    PORT =  server_ip[4] * 256
                          + server_ip[5] * 1;
                }
            }
        }
    }

    socket_close(sock);
    return;
}
static void activate_device(void)
{
    NET_SOCK_ID  sock;
    CPU_SIZE_T   len, slen, rxlen, venlen, osnlen, osvlen;
    CPU_CHAR     length[4];
    CPU_CHAR     NCIK[CIK_LENGTH];
    CPU_CHAR     rx[RX_SIZE];
    CPU_CHAR    *p, *pVEN, *pOSN, *pOSV;
    rdk_meta *meta_info = (rdk_meta *)RDK_META_LOCATION;
    
    pVEN = malloc(VEN_LENGTH * 3 + 1);
    venlen = url_encode(pVEN, VEN_LENGTH * 3 + 1, VEN, VEN_LENGTH);    
    pOSN = malloc(OSN_LENGTH * 3 + 1);
    osnlen = url_encode(pOSN, OSN_LENGTH * 3 + 1, OSN, OSN_LENGTH);
    pOSV = malloc(OSV_LENGTH * 3 + 1);
    osvlen = url_encode(pOSV, OSV_LENGTH * 3 + 1, OSV, OSV_LENGTH);

    len  = 7 + venlen;            // "vendor=",VEN  
    len += 7 + PID_LENGTH;        // "&model=",PID
    len += 4 + MAC_LENGTH;        // "&sn=",MAC
    len += 5 + osnlen;            // "&osn=",OSN
    len += 5 + osvlen;            // "&osv=",OSV
    len += 5 + RDK_META_MFR_SIZE; // "&mfr=",MFRDATA
    
    if (0 == Str_FmtNbr_Int32U (
        (CPU_INT32U)  len,
        (CPU_INT08U)  3,
        (CPU_INT08U)  10,
        (CPU_CHAR)    '\0',
        (CPU_BOOLEAN) DEF_YES,
        (CPU_BOOLEAN) DEF_YES,
        (CPU_CHAR*)   length
    ))
    {
        return;
    }
    slen = Str_Len_N(length, 3);

    sock = socket_open();

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

    if (
        35                != socket_send(sock, "POST /provision/activate HTTP/1.1\r\n", 35) ||
        22                != socket_send(sock, "Host: m2.exosite.com\r\n", 22) ||
        64                != socket_send(sock, "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n", 64) ||
        35                != socket_send(sock, "Accept: text/plain; charset=utf-8\r\n", 35) ||
        16                != socket_send(sock, "Content-Length: ", 16) ||
        slen              != socket_send(sock, length, slen) ||
        4                 != socket_send(sock, "\r\n\r\n", 4) ||
        7                 != socket_send(sock, "vendor=", 7) ||
        venlen            != socket_send(sock, pVEN, venlen) ||        
        7                 != socket_send(sock, "&model=", 7) ||
        PID_LENGTH        != socket_send(sock, PID, PID_LENGTH) ||
        4                 != socket_send(sock, "&sn=", 4) ||
        MAC_LENGTH        != socket_send(sock, MAC, MAC_LENGTH) ||
        5                 != socket_send(sock, "&osn=", 5) ||
        osnlen            != socket_send(sock, pOSN, osnlen) ||
        5                 != socket_send(sock, "&osv=", 5) ||
        osvlen            != socket_send(sock, pOSV, osvlen) ||
        5                 != socket_send(sock, "&mfr=", 5) ||
        RDK_META_MFR_SIZE != socket_send(sock, meta_info->mfr, RDK_META_MFR_SIZE)
    )
    {
        socket_close(sock);
        return;
    
    free(pVEN);    }
    free(pOSN);
    free(pOSV);

    // @HTTP/x.x NNN@
    rxlen = socket_recv(sock, rx, 12);

    if (12 == rxlen && '2' == rx[9] && '0' == rx[10] && '0' == rx[11])
    {
        CPU_CHAR crlf = 0;
        CPU_CHAR ciklen = 0;

        do
        {
            rxlen = socket_recv(sock, rx, RX_SIZE);
            len = rxlen;
            p = rx;

            // Find 4 consecutive \r or \n - should be: \r\n\r\n
            while (0 < len && 4 > crlf)
            {
                if ('\r' == *p || '\n' == *p)
                {
                    ++crlf;
                }
                else
                {
                    crlf = 0;
                }
                ++p;
                --len;
            }

            // The body is the CIK
            if (0 < len && 4 == crlf && CIK_LENGTH > ciklen)
            {
                // TODO, be more robust - match Content-Length header value to CIK_LENGTH
                CPU_CHAR need, part;
                need = CIK_LENGTH - ciklen;
                part = need < len ? need : len;
                Str_Copy_N(NCIK + ciklen, p, part);
                ciklen += part;
            }
        } while (RX_SIZE == rxlen);

        if (CIK_LENGTH == ciklen)
        {
            Exosite_SetCIK(NCIK);
        }
    }

    socket_close(sock);
}