#include "lwip/opt.h"
#include "lwip/arch.h"
#include "lwip/api.h"
#include "lwip/tcp.h"

#include "http_server.h"
#include "web_params_api.h"
#include "parameters.h"
#include "urlcode.h"
#include "trap_params.h"
#include "fsdata.c"
#include "settings_api.h"
#include "netconf.h"
#include "common_config.h"
//#include "testing.h"
#include "rtc.h"
#include "rng.h"
#include "megatec.h"
#include "log.h"
#include "hal.h"

#ifdef PRINTF_STDLIB
#include <stdio.h>
#endif
#ifdef PRINTF_CUSTOM
#include "tinystdio.h"
#endif
#include <string.h>
#include <stdlib.h>

#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"

static int fs_open(char *name, struct fs_file *file);
static err_t http_sent(void *arg, struct tcp_pcb *pcb, u16_t len);
static err_t http_sent_history(void *arg, struct tcp_pcb *pcb, u16_t len);
static err_t http_sent_log(void *arg, struct tcp_pcb *pcb, u16_t len);
static void http_sent_log_err(void * arg, err_t err);
static void send_data(struct tcp_pcb *pcb, struct http_state *hs);
static void HTTP_GetUserCookie(uint8_t user_id, char *str, uint8_t *len);
static uint32_t Parse_Content_Length(char *data, uint32_t len);
static void HTTP_SetUserCookie(char *str, uint8_t user_id);
static void HTTP_UpdateUserLoginTime(uint8_t user_id);
static void HTTP_ForceUserLogout(uint8_t user_id);
void LogoutTimerCallback(TimerHandle_t pxTimer);
int HTTP_ChangeUserPwd(char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut);

SET_PAGE_t SET_PAGE = SET_PAGE_IDLE;

#define SEND_BUF_MAX_LEN   2000
#define RECIVE_BUF_MAX_LEN   1500
char sendBuf[SEND_BUF_MAX_LEN];
uint16_t sendBufLoadLen = 0;

uint16_t printLen = 0;
//char printBuf[1000];

char receiveBuf[RECIVE_BUF_MAX_LEN];
uint16_t receivedBufLen = 0;

#define MAX_POST_REQ_LEN 256
char post_req_data[MAX_POST_REQ_LEN];
uint32_t post_data_count;
uint32_t log_post_reqn;

/* Logout timeout, 30 minutes */
#define WEB_LOGOUT_TIME  configTICK_RATE_HZ*60*30

/* Max user active sessions count */
#define WEB_USER_MAX_SESSION_COUNT  5

typedef struct {
    char cookie[MAX_WEB_COOKIE_LEN];
    TimerHandle_t LogoutTimer;
} auth_session_t;

struct {
    //auth_session_t session[WEB_USER_MAX_SESSION_COUNT];
    char cookie[MAX_WEB_COOKIE_LEN];
    TimerHandle_t LogoutTimer;
} users[MAX_WEB_USERS];

bool Authenticated = false;

/* Level of currently logged-in user */
uint8_t seclevel = 0xFF;

static uint32_t ContentLengthOffset =0;

static const char Content_Length[17] =
/* Content Length */
{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67,0x74, 0x68, 0x3a, 0x20, };

const char HTTP_200_OK[] = "HTTP/1.1 200 OK\r\n\r\n";
/* utf-8 marker to support MS Excel */
const char UTF8_BOM[] = {0xEF, 0xBB, 0xBF, 0x00};

unsigned long log_ptr = 0;
unsigned long log_size = 0;
bool fLogTransInprog = false;

/**
  * @brief  Общая структура настроек
  */
extern SETTINGS_t sSettings;

/**
  * @brief  closes tcp connection
  * @param  pcb: pointer to a tcp_pcb struct
  * @param  hs: pointer to a http_state struct
  * @retval
  */
static void close_conn(struct tcp_pcb *pcb, struct http_state *hs)
{
  tcp_arg(pcb, NULL);
  tcp_sent(pcb, NULL);
  tcp_recv(pcb, NULL);
  mem_free(hs);
  tcp_close(pcb);
}

/**
  * @brief callback function for handling TCP HTTP traffic
  * @param arg: pointer to an argument structure to be passed to callback function
  * @param pcb: pointer to a tcp_pcb structure
  * @param p: pointer to a packet buffer
  * @param err: LwIP error code
  * @retval err
  */
static err_t http_recv(void *arg, struct tcp_pcb *pcb,  struct pbuf *p, err_t err)
{
  char *data;
  struct http_state *hs;
  char CookieBuf[50];
  char *CookiePtr = NULL;
  char name[MAX_WEB_COOKIE_LEN];
  char id[MAX_WEB_COOKIE_LEN];
  uint8_t nameLen = 0, idLen = 0;
  struct fs_file file = {0, 0};
  
  hs = arg;

  if (err == ERR_OK && p != NULL)
  {
    tcp_recved(pcb, p->tot_len);
  
	if (hs->file == NULL)
    {
      data = p->payload;
/*	  
	  printLen = p->tot_len;
	  memcpy(printBuf, p->payload , printLen);
	  printf(printBuf);
*/	  
	  receivedBufLen = p->tot_len;
	  memcpy(receiveBuf, p->payload , receivedBufLen);

	  receiveBuf[receivedBufLen] = '\0';
	 // printf("receive %s \r\n", receiveBuf);
	  /* Get cookie "uname" value */
	  CookiePtr = strstr(receiveBuf, "uname=");
	  strncpy(CookieBuf, CookiePtr, 50);
	  //printf("********CookieBuf1= %s\r\n", CookieBuf);
	  memset(name, 0, MAX_WEB_COOKIE_LEN);
	  GetCookieValue(CookieBuf, "uname=", name, &nameLen);
	  //printf("********CookieBuf2= %s\r\n", CookieBuf);
	  //printf("********uname= %s\r\n", name);

	   /* Get cookie "id" value */
	   CookiePtr = strstr(receiveBuf, "id=");
	   strncpy(CookieBuf, CookiePtr, 50);
	   //printf("********CookieBuf1= %s\r\n", CookieBuf);
	   memset(id, 0, MAX_WEB_COOKIE_LEN);
	   GetCookieValue(CookieBuf, "id=", id, &idLen);
	   //printf("********CookieBuf2= %s\r\n", CookieBuf);
	   //printf("********id= %s\r\n", id);


	   /* Id of currently logged-in user */
	   uint8_t user_id;

	   /* Level of currently logged-in user */
	   seclevel = 0xFF;
	   for (user_id = 0; user_id < MAX_WEB_USERS; user_id++) {
		   HTTP_GetUserCookie(user_id, CookieBuf, &idLen);
		   if (strncmp(id, CookieBuf, idLen) == 0 ) {
			   GetUserLevelInt(user_id, &seclevel);
			   Authenticated = true;
			   break;
		   }
		   Authenticated = false;
		   seclevel = 0xFF;
	   }

	   if ( Authenticated == false && sSettings.sRADIUS.Auth_enable == false)
	   {
		  HTTP_LOGIN(sendBuf, &sendBufLoadLen);

		  hs->file = sendBuf;
		  hs->left = sendBufLoadLen;
		  send_data(pcb, hs);
		  tcp_sent(pcb, http_sent);
	   }

	   else if ( Authenticated == false )//&& sSettings.sRADIUS.Auth_enable == true
	  {
		  if (strncmp(data, "GET /main.css", 13) == 0) // +
		  {
			fs_open("/main.css", &file);
			 hs->file = file.data;
			 hs->left = file.len;
			 send_data(pcb, hs);
			 tcp_sent(pcb, http_sent);
		  }
		  else if (strncmp(data, "GET /rotek.png", 14) == 0) // +
		  {
			fs_open("/rotek.png", &file);
			 hs->file = file.data;
			 hs->left = file.len;
			 send_data(pcb, hs);
			 tcp_sent(pcb, http_sent);
		  }
		else if (strncmp(data, "GET /favicon.ico", 16) == 0) // ?
		{
			 fs_open("/favicon.ico", &file);
			 hs->file = file.data;
			 hs->left = file.len;
			 send_data(pcb, hs);
			 tcp_sent(pcb, http_sent);
		}
		else if (strncmp(data, "GET /role.js", 12) == 0)
		{
		  fs_open("/role.js", &file);
		  hs->file = file.data;
		  hs->left = file.len;
		  send_data(pcb, hs);
		  tcp_sent(pcb, http_sent);

		}
		  else if ((strncmp(data, "POST /login.cgi", 15) == 0) || (log_post_reqn > 0))
			{
			  uint32_t i, offset = 0, req_data_received = 0;

			  //printf("request 1: %d\r\n", receivedBufLen);

			  /* parse packet for Content-length field */
			  post_data_count = Parse_Content_Length(data, p->tot_len);
			  //printf("Content-length: %d\r\n", (int)post_data_count);

			  if (post_data_count < MAX_POST_REQ_LEN) {

				  memset(post_req_data, 0, MAX_POST_REQ_LEN);

					/* parse packet for "\r\n\r\n" */
					for (i = 0; i < receivedBufLen; i++)
					{
						if (strncmp ((char*)(data+i), "\r\n\r\n", 4) == 0)
						{
							offset = i+4;
							//printf("offset: %d\r\n", (int)offset);
							break;
						}
					}

					req_data_received = receivedBufLen - offset;
					//printf("req data received: %d\r\n", (int)req_data_received);

					/* Check if "\r\n\r\n" was found */
					if (offset != 0) {

						/* if data was splited in two packets */
						if (req_data_received < post_data_count) {
							/* Copy request data to buffer */
							snprintf(post_req_data, req_data_received, "%s", receiveBuf);
							//printf("copied: %d\r\n", (int)req_data_received);

							post_data_count -= req_data_received;
						}
						/* if data received completely */
						else {

							strncat(post_req_data, (char *)(data + offset), post_data_count);
							//printf("post_req_data: %s\r\n", post_req_data);

							if (HTTP_ConfirmWebPwd(post_req_data, sendBuf, strlen(post_req_data), &sendBufLoadLen) == SEND_REQUIRED_YES) {

								  hs->file = sendBuf;
								  hs->left = sendBufLoadLen;
								  send_data(pcb, hs);
								  tcp_sent(pcb, http_sent);

							}
							else {
								/* Redirect to login page */
								fs_open("/login.html", &file);
								hs->file = file.data;
								hs->left = file.len;
								send_data(pcb, hs);
								tcp_sent(pcb, http_sent);
							}

							/* End reqest */
							post_data_count = 0;
							log_post_reqn = 0;
						}
					}
					/* request was fragmented before "\r\n\r\n" */
					else {
						//printf("no data found!\r\n");

						/* wait next packet */
						log_post_reqn++;

						/* wait max 2 requests */
						if (log_post_reqn > 1) {
							/* Redirect to login page */
							fs_open("/login.html", &file);
							hs->file = file.data;
							hs->left = file.len;
							send_data(pcb, hs);
							tcp_sent(pcb, http_sent);
	
							/* End reqest */
							post_data_count = 0;
							log_post_reqn = 0;
						}
					}
			  }
			  else {
				  printf("Too long POST request!\r\n");
				  /* Ignore request */
				  post_data_count = 0;
				  log_post_reqn = 0;

					/* Redirect to login page */
					fs_open("/login.html", &file);
					hs->file = file.data;
					hs->left = file.len;
					send_data(pcb, hs);
					tcp_sent(pcb, http_sent);
			  }
			}
			  else if (post_data_count > 0)
				{
				  strncat(post_req_data, data, post_data_count);
				  //printf("copied: %d\r\n", (int)post_data_count);
				  //printf("post_req_data: %s\r\n", post_req_data);

				  if (HTTP_ConfirmWebPwd(post_req_data, sendBuf, strlen(post_req_data), &sendBufLoadLen) == SEND_REQUIRED_YES) {

						hs->file = sendBuf;
						hs->left = sendBufLoadLen;
						send_data(pcb, hs);
						tcp_sent(pcb, http_sent);

				  }
				  else {
					  /* Redirect to login page */
					  fs_open("/login.html", &file);
					  hs->file = file.data;
					  hs->left = file.len;
					  send_data(pcb, hs);
					  tcp_sent(pcb, http_sent);
				  }

				  /* End reqest */
				  post_data_count = 0;
				  log_post_reqn = 0;
				}
		  else
		  {
			  fs_open("/login.html", &file);
			  hs->file = file.data;
			  hs->left = file.len;
			  send_data(pcb, hs);
			  tcp_sent(pcb, http_sent);
		  }

	  }

	  else if ( Authenticated == true ) {

	  if (strncmp(data, "GET /main.css", 13) == 0) // +
	  {
	    fs_open("/main.css", &file);
        hs->file = file.data;
        hs->left = file.len;
        send_data(pcb, hs);
        tcp_sent(pcb, http_sent);
	  }
	  else if (strncmp(data, "GET /rotek.png", 14) == 0) // +
	  {
	    fs_open("/rotek.png", &file);
        hs->file = file.data;
        hs->left = file.len;
        send_data(pcb, hs);
        tcp_sent(pcb, http_sent);
	  }
      else if (strncmp(data, "GET /favicon.ico", 16) == 0) // ?                 
      {                                                                     
        fs_open("/favicon.ico", &file);                                     
        hs->file = file.data;                                               
        hs->left = file.len;                                                
        send_data(pcb, hs);                                                 
        tcp_sent(pcb, http_sent);                                           
      }
	  else if (strncmp(data, "GET /main.js", 12) == 0) // +
	  {
	    fs_open("/main.js", &file);
        hs->file = file.data;
        hs->left = file.len;
        send_data(pcb, hs);
        tcp_sent(pcb, http_sent);
		
	  }
	  else if (strncmp(data, "GET /role.js", 12) == 0)
	  {
		fs_open("/role.js", &file);
		hs->file = file.data;
		hs->left = file.len;
		send_data(pcb, hs);
		tcp_sent(pcb, http_sent);

	  }
	  else if (strncmp(data, "GET /settings.html", 18) == 0) // +
	  {
		HTTP_UpdateUserLoginTime(user_id);
		if (seclevel == 0){
			fs_open("/settings.html", &file);
			hs->file = file.data;
			hs->left = file.len;
			send_data(pcb, hs);
			tcp_sent(pcb, http_sent);
		}
		else {
			fs_open("/index.html", &file);
			hs->file = file.data;
			hs->left = file.len;
			send_data(pcb, hs);
			tcp_sent(pcb, http_sent);
		}
	  }
	  else if (strncmp(data, "GET /info.html", 14) == 0) // +
	  {
		HTTP_UpdateUserLoginTime(user_id);
	    fs_open("/info.html", &file);
        hs->file = file.data;
        hs->left = file.len;
        send_data(pcb, hs);
        tcp_sent(pcb, http_sent);
	  }
	  else if (strncmp(data, "GET /history.html", 17) == 0)
	  {
		HTTP_UpdateUserLoginTime(user_id);
		fs_open("/history.html", &file);
		hs->file = file.data;
		hs->left = file.len;
		send_data(pcb, hs);
		tcp_sent(pcb, http_sent);
	  }
	  else if (strncmp(data, "GET /ups_history.html", 21) == 0)
	  {
		HTTP_UpdateUserLoginTime(user_id);
		fs_open("/ups_history.html", &file);
		hs->file = file.data;
		hs->left = file.len;
		send_data(pcb, hs);
		tcp_sent(pcb, http_sent);
	  }
	  else if (strncmp(data, "GET /getJson.cgi", 16) == 0) // +
	  {
		HTTP_GetParamsPage1(sendBuf);
		hs->file = sendBuf;
        hs->left = strlen(sendBuf);
		send_data(pcb, hs);
		tcp_sent(pcb, http_sent);
	  }	  
	  else if (strncmp(data, "GET /settings.cgi", 17) == 0) // +
	  {
		SET_PAGE = SET_PAGE_PAGE2;
		
		if (seclevel == 0) {
			if (HTTP_SettingsPage(receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen) == SEND_REQUIRED_YES)
			{
			  hs->file = sendBuf;
			  hs->left = sendBufLoadLen;
			  send_data(pcb, hs);
			  tcp_sent(pcb, http_sent);
			}
			/*else
			{
			  fs_open("/settings.html", &file);
			  hs->file = file.data;
			  hs->left = file.len;
			  send_data(pcb, hs);
			  tcp_sent(pcb, http_sent);
			}*/
		}
	  }
	  else if (strncmp(data, "POST /settings.cgi", 18) == 0)
	  {
		  //strncat(&receiveBuf,  " ", 1);
          strncat(receiveBuf,  " ", 1);
		  HTTP_SetSettings(receiveBuf, receivedBufLen);
		  memset(sendBuf, 0, SEND_BUF_MAX_LEN);

		  strcpy(sendBuf, "HTTP/1.1 200 OK\r\n");
		  strcat(sendBuf, "\r\n\r\n");
		  strcat(sendBuf,"<!DOCTYPE html><html lang=""><head><meta http-equiv=\"refresh\" content=\"0;url=/settings.html\"/></head></html>\r\n\r\n");

		  sendBufLoadLen = strlen(sendBuf);
		  hs->file = sendBuf;
		  hs->left = sendBufLoadLen;
		  send_data(pcb, hs);
		  tcp_sent(pcb, http_sent);
	  }
	  else if (strncmp(data, "GET /info.cgi", 13) == 0) // +
	  {
			if (HTTP_InfoPage(receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen) == SEND_REQUIRED_YES)
			{
			  hs->file = sendBuf;
			  hs->left = sendBufLoadLen;
			  send_data(pcb, hs);
			  tcp_sent(pcb, http_sent);
			}
		/*	else
			{
			  fs_open("/info.html", &file);
			  hs->file = file.data;
			  hs->left = file.len;
			  send_data(pcb, hs);
			  tcp_sent(pcb, http_sent);
			}*/
	  }
	  else if (strncmp(data, "POST /info.cgi", 14) == 0)
	  {
		  //strncat(&receiveBuf,  " ", 1);
          strncat(receiveBuf,  " ", 1);
		  HTTP_SetInfo(receiveBuf, receivedBufLen);
		  memset(sendBuf, 0, SEND_BUF_MAX_LEN);

		  strcpy(sendBuf, "HTTP/1.1 200 OK\r\n");
		  strcat(sendBuf, "\r\n\r\n");
		  strcat(sendBuf,"<!DOCTYPE html><html lang=""><head><meta http-equiv=\"refresh\" content=\"0;url=/info.html\"/></head></html>\r\n\r\n");

		  sendBufLoadLen = strlen(sendBuf);
		  hs->file = sendBuf;
		  hs->left = sendBufLoadLen;
		  send_data(pcb, hs);
		  tcp_sent(pcb, http_sent);
	  }
	  else if (strncmp(data, "GET /history.cgi", 16) == 0)
		{
		  int res;

		  res = HTTP_HistoryPage(receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen);

		  if (res == SEND_REQUIRED_FILE)
		  {
			  hs->file = sendBuf;
			  hs->left = sendBufLoadLen;
			  send_data(pcb, hs);
			  tcp_sent(pcb, http_sent_history);
			  tcp_err(pcb, http_sent_log_err);
		  }
		  else if (res == SEND_REQUIRED_YES) {
			  hs->file = sendBuf;
			  hs->left = sendBufLoadLen;
			  send_data(pcb, hs);
			  tcp_sent(pcb, http_sent);
		  }
		}
	else if (strncmp(data, "GET /ups_history.cgi", 19) == 0)
	{
	  int res;

	  res = HTTP_UpsHistoryPage(receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen);

	  if (res == SEND_REQUIRED_FILE)
	  {
		  hs->file = sendBuf;
		  hs->left = sendBufLoadLen;
		  send_data(pcb, hs);
		  tcp_sent(pcb, http_sent_log);
		  tcp_err(pcb, http_sent_log_err);
	  }
	  else if (res == SEND_REQUIRED_YES) {
		  hs->file = sendBuf;
		  hs->left = sendBufLoadLen;
		  send_data(pcb, hs);
		  tcp_sent(pcb, http_sent);
	  }
	}
	  /* Тест  АКБ ИБП */
	  else if (strncmp(data, "POST /bat_test.cgi", 18) == 0)
	  {
		HTTP_UPSTest(receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen);

		hs->file = sendBuf;
		hs->left = sendBufLoadLen;
		send_data(pcb, hs);
		tcp_sent(pcb, http_sent);
	  }
	  /* Выключение ИБП */
	  else if (strncmp(data, "POST /ups_power.cgi", 19) == 0)
	  {
		HTTP_UPSshutdown(receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen);

		hs->file = sendBuf;
		hs->left = sendBufLoadLen;
		send_data(pcb, hs);
		tcp_sent(pcb, http_sent);
	  }
	  /* Сброс настроек и сохранине */
	  else if (strncmp(data, "GET /reset.cgi", 14) == 0)
	  {
		HTTP_ResetSettings();
		HTTP_SaveSettings();

		fs_open("/settings.html", &file);
		hs->file = file.data;
		hs->left = file.len;
		send_data(pcb, hs);
		tcp_sent(pcb, http_sent);
	  }
	  /* Перезагрузка контроллера */
	  else if (strncmp(data, "GET /reboot.cgi", 15) == 0)
	  {
		HTTP_Reboot();
	  }
	  /* Подтверждение новых сетевых настроек */
	  else if (strncmp(data, "GET /confirm.cgi", 16) == 0)
	  {
		SetWebReinitFlag(false);
		SetConfirmWebParamsFlag();

		fs_open("/index.html", &file);
		hs->file = file.data;
		hs->left = file.len;
		send_data(pcb, hs);
		tcp_sent(pcb, http_sent);
	  }
	  /* Проверка пароля, переход в bootloader */
	  else if (strncmp(data, "GET /fw_update.cgi", 18) == 0)
	  {
		HTTP_ConfirmBootPwd(receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen);

		hs->file = sendBuf;
		hs->left = sendBufLoadLen;
		send_data(pcb, hs);
		tcp_sent(pcb, http_sent);
	  }
	  /* Смена пароля пользователя */
	  else if (strncmp(data, "POST /changepwd.cgi", 19) == 0)
	  {
		  HTTP_ChangeUserPwd(receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen);

		  hs->file = sendBuf;
		  hs->left = sendBufLoadLen;
		  send_data(pcb, hs);
		  tcp_sent(pcb, http_sent);
	  }
	  // На производстве
	  else if (strncmp(data, "GET /setProdate.cgi", 19) == 0)
	  {
		HTTP_Prodate(receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen);

		hs->file = sendBuf;
		hs->left = sendBufLoadLen;
		send_data(pcb, hs);
		tcp_sent(pcb, http_sent);
	  }
	  else
	  {
		HTTP_UpdateUserLoginTime(user_id);
		fs_open("/index.html", &file); // +
		hs->file = file.data;
		hs->left = file.len;
		send_data(pcb, hs);
		tcp_sent(pcb, http_sent);
	  }
	}
    }
    pbuf_free(p);
   // close_conn(pcb,hs);
  }
/*  if (err == ERR_OK && p == NULL)
  {
    close_conn(pcb, hs);
  }*/
  return ERR_OK;
} 


/**
  * @brief Error callback for log file transfer
  */
static void http_sent_log_err(void * arg, err_t err)
{
    (void)err;
    (void)arg;
    /* Clear file transfer in progress flag */
    fLogTransInprog = false;
}


/**
  * @brief Sent callback for log file transfer (messages as is, not ordered)
  */
static err_t http_sent_log(void *arg, struct tcp_pcb *pcb, u16_t len)
{
  struct http_state *hs;
  uint32_t nbytes = 0;
  static bool start = true;
  (void)len;

  hs = arg;

  if (hs->left > 0)
  {
    send_data(pcb, hs);
  }
  else
  {
	  memset(logFileBuf, 0, FILE_BUF_MAX_LEN);
      if (log_ptr + FILE_BUF_MAX_LEN_LOG <= log_size) {
          nbytes = LOG_GetData(log_ptr, logFileBuf, FILE_BUF_MAX_LEN_LOG, start);
      }
      else if (log_ptr < log_size) {
          nbytes = LOG_GetData(log_ptr, logFileBuf, (log_size - log_ptr), start);
      }
      else {
          nbytes = 0;
      }
      log_ptr += nbytes;

      start = false;
      if (nbytes == 0) {
          /* File transfer finished. */
          start = true;
          close_conn(pcb, hs);

          /* Clear file transfer in progress flag */
          fLogTransInprog = false;

          return ERR_OK;
      }

      hs->file = logFileBuf;
      hs->left = nbytes;
      send_data(pcb, hs);
      tcp_sent(pcb, http_sent_log);

  }
  return ERR_OK;
}

/**
  * @brief Sent callback for log file transfer (messages as is, not ordered)
  */
static err_t http_sent_history(void *arg, struct tcp_pcb *pcb, u16_t len)
{
  struct http_state *hs;
  uint32_t nbytes = 0;
  static bool start = true;
  (void)len;

  hs = arg;

  if (hs->left > 0)
  {
    send_data(pcb, hs);
  }
  else
  {
	  memset(logFileBuf, 0, FILE_BUF_MAX_LEN);
      if (log_ptr + FILE_BUF_MAX_LEN <= log_size) {
          nbytes = History_GetData(log_ptr, logFileBuf, FILE_BUF_MAX_LEN, start);
      }
      else if (log_ptr < log_size) {
          nbytes = History_GetData(log_ptr, logFileBuf, (log_size - log_ptr), start);
      }
      else {
          nbytes = 0;
      }
      log_ptr += nbytes;

      start = false;
      if (nbytes == 0) {
          /* File transfer finished. */
          start = true;
          close_conn(pcb, hs);

          /* Clear file transfer in progress flag */
          fLogTransInprog = false;

          return ERR_OK;
      }

      hs->file = logFileBuf;
      hs->left = nbytes;
      send_data(pcb, hs);
      tcp_sent(pcb, http_sent_history);

  }
  return ERR_OK;
}


/**
  * @brief  callback function for handling connection errors
  * @param  arg: pointer to an argument to be passed to callback function
  * @param  err: LwIP error code   
  * @retval none
  */
static void conn_err(void *arg, err_t err)
{
  struct http_state *hs;

  hs = arg;
  mem_free(hs);
}

/**
  * @brief callback function called after a successfull TCP data packet transmission  
  * @param arg: pointer to an argument to be passed to callback function
  * @param pcb: pointer on tcp_pcb structure
  * @param len
  * @retval err : LwIP error code
  */
static err_t http_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
  struct http_state *hs;

  hs = arg;

  if (hs->left > 0)
  {
    send_data(pcb, hs);
  }
  else
  {
    close_conn(pcb, hs);      
  }
  return ERR_OK;
}

/**
  * @brief sends data found in  member "file" of a http_state struct
  * @param pcb: pointer to a tcp_pcb struct
  * @param hs: pointer to a http_state struct
  * @retval none
  */
static void send_data(struct tcp_pcb *pcb, struct http_state *hs)
{
  err_t err;
  u16_t len;

  /* We cannot send more data than space available in the send
     buffer */
  if (tcp_sndbuf(pcb) < hs->left)
  {
    len = tcp_sndbuf(pcb);
  }
  else
  {
    len = hs->left;
  }
  err = tcp_write(pcb, hs->file, len, 0);
  if (err == ERR_OK)
  {
    hs->file += len;
    hs->left -= len;
  }
}

/**
  * @brief tcp poll callback function
  * @param arg: pointer to an argument to be passed to callback function
  * @param pcb: pointer on tcp_pcb structure
  * @retval err_t
  */
static err_t http_poll(void *arg, struct tcp_pcb *pcb)
{
  if (arg == NULL)
  {
    tcp_close(pcb);
  }
  else
  {
    send_data(pcb, (struct http_state *)arg);
  }
  return ERR_OK;
}

/**
  * @brief  callback function on TCP connection setup ( on port 80)
  * @param  arg: pointer to an argument structure to be passed to callback function
  * @param  pcb: pointer to a tcp_pcb structure
  * &param  err: Lwip stack error code
  * @retval err
  */
static err_t http_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
  struct http_state *hs;

  /* Allocate memory for the structure that holds the state of the connection */
  hs = mem_malloc(sizeof(struct http_state));

  if (hs == NULL)
  {
    return ERR_MEM;
  }

  /* Initialize the structure. */
  hs->file = NULL;
  hs->left = 0;

  /* Tell TCP that this is the structure we wish to be passed for our
     callbacks. */
  tcp_arg(pcb, hs);

  /* Tell TCP that we wish to be informed of incoming data by a call
     to the http_recv() function. */
  tcp_recv(pcb, http_recv);

  tcp_err(pcb, conn_err);

  tcp_poll(pcb, http_poll, 10);
  return ERR_OK;
}

/**
  * @brief  Opens a file defined in fsdata.c ROM filesystem 
  * @param  name : pointer to a file name
  * @param  file : pointer to a fs_file structure  
  * @retval  1 if success, 0 if fail
  */
static int fs_open(char *name, struct fs_file *file)
{
  struct fsdata_file_noconst *f;

  for (f = (struct fsdata_file_noconst *)FS_ROOT; f != NULL; f = (struct fsdata_file_noconst *)f->next)
  {
    if (!strcmp(name, f->name))
    {
      file->data = f->data;
      file->len = f->len;
      return 1;
    }
  }
  return 0;
}

/**
  * @brief  Initialize the HTTP server (start its thread) 
  * @param  none
  * @retval None
  */
void HTTP_Init()
{
	char buf[MAX_WEB_COOKIE_LEN];
	  uint8_t user_id;
  //sys_thread_new("HTTP", http_server_netconn_thread, NULL, 3000, 2);
  struct tcp_pcb *pcb;
  /*create new pcb*/
  pcb = tcp_new();
  /* bind HTTP traffic to pcb */
  tcp_bind(pcb, IP_ADDR_ANY, 80);
  /* start listening on port 80 */
  pcb = tcp_listen(pcb);
  /* define callback function for TCP connection setup */
  tcp_accept(pcb, http_accept);
  for (user_id = 0; user_id < MAX_WEB_USERS; user_id++) {
     /* Flush user cookie by random value */
     sprintf(buf, "%X", (unsigned int)GetRandomNumber());
     HTTP_SetUserCookie(buf, user_id);

     /* Create user logout timers */
     //users[user_id].LogoutTimer =
     //        xTimerCreate("LogoutTmr", WEB_LOGOUT_TIME, pdFALSE, ( void * ) user_id, LogoutTimerCallback);
   }
}

/**
  * @brief  
  * @retval None
  */
int HTTP_SettingsPage(char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut)
{
  char tempStr[30];
  strncpy(tempStr, bufIn, 30);
  
  /* В запросе нет параметров, нужно формировать JSON ответ */
  if (strpbrk(tempStr,"?") == 0)
  {
	memset(bufOut, 0, SEND_BUF_MAX_LEN);
	
	HTTP_GetSettings(bufOut);
	
    //printf(bufOut);
    
    *lenBufOut = strlen(bufOut);
	
	return SEND_REQUIRED_YES;
  }
  /* В запросе есть параметры, нужно парсить и сохранять настройки */
  else
  {
	//HTTP_SetSettings(bufIn, lenBufIn);
	
    return SEND_REQUIRED_NO;
  }
}

/**
  * @brief  
  * @retval None
  */
int HTTP_InfoPage(char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut)
{
  char tempStr[30];
  strncpy(tempStr, bufIn, 30);
  
  /* В запросе нет параметров, нужно формировать JSON ответ */
  if (strpbrk(tempStr,"?") == 0)
  {
	memset(bufOut, 0, SEND_BUF_MAX_LEN);
	
	HTTP_GetInfo(bufOut);
		
    *lenBufOut = strlen(bufOut);
	
	return SEND_REQUIRED_YES;
  }
  /* В запросе есть параметры, нужно парсить и сохранять настройки */
  else
  {
	//HTTP_SetInfo(bufIn, lenBufIn);
	return SEND_REQUIRED_NO;
/*	
	HTTP_SetSettings(bufIn, lenBufIn);
    return SEND_REQUIRED_NO;
*/	
  }
}  

int HTTP_HistoryPage(char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut)
{
  uint8_t i, valueLen = 0;
  char value[20];
  uint32_t nbytes = 0;

  (void)lenBufIn;

  memset(bufOut, 0, FILE_BUF_MAX_LEN);

  ClearParamString(bufIn);

  memset(value, 0, 20);
  GetParamValue(bufIn, "page=", value, &valueLen);

  if (strcmp(value, "all") == 0)
  {
	  if (!LOG_IsInit()) {
		  return SEND_REQUIRED_NO;
	  }

      if (fLogTransInprog == false) {

        // Send log as raw data
        log_ptr = 0;

        log_size = History_GetTotalSTRCount() * STRING_SIZE_HISTORY + sizeof(UTF8_BOM)-1;
        sprintf(bufOut, "HTTP/1.1 200 OK\r\nContent-Length:%lu\r\n\r\n%s", log_size, UTF8_BOM);

        *lenBufOut = strlen(bufOut);

        // Set file transfer in progress flag
        fLogTransInprog = true;

        return SEND_REQUIRED_FILE;
     }
     else {
          // We send nothing if file transfer already in progress
          return SEND_REQUIRED_NO;
     }
  }
  else {
	  if (!LOG_IsInit()) {
		  return SEND_REQUIRED_NO;
	  }
	  else {
		  HTTP_GetHistoryPage(bufOut, atoi(value));
		  *lenBufOut = strlen(bufOut);

		  return SEND_REQUIRED_YES;
	  }
  }
}

int HTTP_UpsHistoryPage(char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut)
{
  uint8_t i, valueLen = 0;
  char value[20];
  uint32_t nbytes = 0;

  (void)lenBufIn;

  memset(bufOut, 0, FILE_BUF_MAX_LEN);

  ClearParamString(bufIn);

  memset(value, 0, 20);
  GetParamValue(bufIn, "page=", value, &valueLen);

  if (strcmp(value, "all") == 0)
  {
	  if (!LOG_IsInit()) {
		  return SEND_REQUIRED_NO;
	  }

      if (fLogTransInprog == false) {

        // Send log as raw data
        log_ptr = 0;

        log_size = LOG_GetTotalSTRCount() * STRING_SIZE + sizeof(UTF8_BOM)-1;
        sprintf(bufOut, "HTTP/1.1 200 OK\r\nContent-Length:%lu\r\n\r\n%s", log_size, UTF8_BOM);

        *lenBufOut = strlen(bufOut);

        // Set file transfer in progress flag
        fLogTransInprog = true;

        return SEND_REQUIRED_FILE;
     }
     else {
          // We send nothing if file transfer already in progress
          return SEND_REQUIRED_NO;
     }
  }
  else {
	  if (!LOG_IsInit()) {
		  return SEND_REQUIRED_NO;
	  }
	  else {
		  HTTP_GetUpsHistoryPage(bufOut, atoi(value));
		  *lenBufOut = strlen(bufOut);

		  return SEND_REQUIRED_YES;
	  }
  }
}
  
/**
  * @brief  Установка даты производства
  */
// TODO Убрать заглушку!
void HTTP_Prodate(char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut)
{
  uint8_t valueLen = 0;
  char value[20];
  
  memset(bufOut, 0, SEND_BUF_MAX_LEN);
  
  ClearParamString(bufIn);
  
  memset(value, 0, 20);
  GetParamValue(bufIn, "prodate=", value, &valueLen);
  /*
  printf("Prodate: ");
  printf(value);
  printf("\r\n");
  */
  
  /* Устанавливаем дату производства */
  SETTINGS_SetProDate(value, valueLen);
  
  /* Устанавливаем дату следующей профилактики +1 год */
  RTC_SetProfTime(value);
  
  /* Пока отправляем true */
  strcpy(bufOut, "HTTP/1.0 200 OK\r\nContent-Type:text/html\r\n\r\nTrue");
  *lenBufOut = strlen(bufOut);
  
 // TEST_SetServerFlag();
}

/**
  * @brief  
  * @retval None
  */
void HTTP_SetSettings(char *buf, uint16_t lenBuf)
{
  uint8_t valueLen = 0;
  const uint8_t len = MAX_WEB_PARAM_LEN;
  char value[MAX_WEB_PARAM_LEN];
  char str[MAX_WEB_PARAM_LEN];

  //printf(buf);
  
  //ClearParamString(buf);
  
  memset(value, 0, len);
  memset(str, 0, MAX_WEB_PARAM_LEN);
  
  /* SNMP */
  GetParamValue(buf, "read_community=", value, &valueLen);
  SetReadCommunity(value);
  memset(value, 0, len);
  
  GetParamValue(buf, "write_community=", value, &valueLen);
  SetWriteCommunity(value);
  memset(value, 0, len);
      
  GetParamValue(buf, "managerIP=", value, &valueLen);
  SetManagerIp(value);
  memset(value, 0, len);

  GetParamValue(buf, "managerIP2=", value, &valueLen);
  SetManagerIp2(value);
  memset(value, 0, len);

  GetParamValue(buf, "managerIP3=", value, &valueLen);
  SetManagerIp3(value);
  memset(value, 0, len);
  
  GetParamValue(buf, "managerIP4=", value, &valueLen);
  SetManagerIp4(value);
  memset(value, 0, len);

  GetParamValue(buf, "managerIP5=", value, &valueLen);
  SetManagerIp5(value);
  memset(value, 0, len);

  /* Сетевые параметры */
  GetParamValue(buf, "dhcp=", value, &valueLen);
  SetDhcpStateStr(value);
  
  if (strncmp(value, "on", 2) != 0)  // Если dhcp off устанавливаем параметры
    {
    memset(value, 0, len);

    GetParamValue(buf, "ipaddr=", value, &valueLen);
    SetIPStr(value);
    memset(value, 0, len);
  
    GetParamValue(buf, "gw=", value, &valueLen);
    SetGatewayStr(value);
    memset(value, 0, len);
  
    GetParamValue(buf, "mask=", value, &valueLen);
    SetMaskStr(value);
    memset(value, 0, len);
  }
  memset(value, 0, len);

  GetParamValue(&buf[555], "auth=", value, &valueLen);
  SetAuthEnableStateStr(value);

  if (strncmp(value, "on", 2) == 0){
		/* параметры RADIUS*/
	  memset(value, 0, len);
		GetParamValue(buf, "rs_enabled=", value, &valueLen);
		SetRDSEnableStateStr(value);

		if (strncmp(value, "on", 2) == 0)  // Если raddius off устанавливаем параметры
		{
			memset(value, 0, len);
			GetParamValue(buf, "rs_server=", value, &valueLen);
			SetRDSIpStr(value);
			memset(value, 0, len);

			GetParamValue(buf, "rs_port=", value, &valueLen);
			SetRDSPortStr(value);
			memset(value, 0, len);

			GetParamValue(buf, "rs_pwd=", value, &valueLen);
			SetRDSPasswordkStr(value);
			memset(value, 0, len);

			GetParamValue(buf, "rs_key=", value, &valueLen);
			SetRDSKeyAccesstStr(value);
			memset(value, 0, len);
		}
  }
  memset(value, 0, len);

  // Параметры реле и сухих контактов
  GetParamValue(buf, "di1=", value, &valueLen);
  SetDINTypeActStr(value, 0);
  memset(value, 0, len);

  GetParamValue(buf, "ro1=", value, &valueLen);
  SetROTypeActStr(value, 0);
  memset(value, 0, len);

  GetParamValue(buf, "ro2=", value, &valueLen);
  SetROTypeActStr(value, 1);
  memset(value, 0, len);


  // Параметры даты и времени
  GetParamValue(buf, "ntp=", value, &valueLen);
  SetSntpStateStr(value);

  if (strncmp(value, "1", 1) == 0)  // Если ntp on устанавливаем параметры
  {
    memset(value, 0, len);

    GetParamValue(buf, "ntpservip=", value, &valueLen);
    SetSntpServerIpStr(value);
    memset(value, 0, len);
  }
  else if (strncmp(value, "0", 1) == 0){
      GetParamValue(buf, "date=", value, &valueLen);
      SetDateStr(value);
      memset(value, 0, len);
      GetParamValue(buf, "time=", value, &valueLen);
      url_decode(str, sizeof(str), value);
      SetTimeStr(str);
      memset(value, 0, len);
  }

  GetParamValue(buf, "utc=", value, &valueLen);
  SetSntpTimeZoneStr(value);
  memset(value, 0, len);
  
  /* Если параметры WEB изменились выставляем флаг, сохраняем настройки и перезагружаемся */
  if (GetStateWebReinit() == true)
  {	
	SetWebReinitFlag(true);
	HTTP_SaveSettings();
    /* Блокируем управление ключем на тау секунд*/
    //IO_KeyBlockOn();
    vTaskDelay(1010);
    Reboot();
  }	
  
  HTTP_SaveSettings();
}

/**
  * @brief  
  * @retval None
  */
void HTTP_SetInfo(char *buf, uint16_t lenBuf)
{
  uint8_t valueLen = 0;
  const uint8_t len = 110;
  char value[110];
  char str[110];

 // ClearParamString(buf);
  
  memset(value, 0, len);
  
  /* Владелец */
  GetParamValue(buf, "owner=", value, &valueLen);
  url_decode(str, sizeof(str), value);
  SetOwner(str);
  memset(value, 0, len);
  
  /* Владелец */
  GetParamValue(buf, "sysLocation=", value, &valueLen);
  url_decode(str, sizeof(str), value);
  SetLocation(str);
  memset(value, 0, len);
  
  /* Комментарий */
  GetParamValue(buf, "comment=", value, &valueLen);
  url_decode(str, sizeof(str), value);
  SetComment(str);
  memset(value, 0, len);
 
  HTTP_SaveSettings();
}

/**
  * @brief  Запуск/останов теста UPS
  */
void HTTP_UPSTest(char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut)
{
	  char *value = 0;
	  char *valueLen = 0;
	  char tempValue[20];
	  char tempValue2[20];
	  int8_t res = 0;

	  memset(tempValue, 0, 20);
	  memset(tempValue2, 0, 20);

	  strcpy(bufOut, HTTP_200_OK);

	  value = strstr(bufIn, "func");
	  valueLen = strpbrk(value, ":");
	  strncpy(tempValue, (valueLen+1), (strlen(valueLen)-2));
	  if (strcmp(tempValue, "\"stop\"") == 0){
		  res = ups_metac_service_pdu(ups_cancel_test);
		  if(res == 1 || res == 0){
			  strcat(bufOut, "Тест остановлен!");
			  log_event_data(LOG_TEST_UPS, "Администратор(Останов)");
		  }
		  if(res == -1)
			  strcat(bufOut, "Тест не удалось остановить!");
		  *lenBufOut = strlen(bufOut);
	  }
	  else if (strcmp(tempValue, "\"discharge\"") == 0){
		  res = ups_metac_service_pdu(ups_test_low_bat);
		  if(res == 1 || res == 0){
			  strcat(bufOut, "Тест запущен!");
			  log_event_data(LOG_TEST_UPS, "Администратор (Запущен)");
		  }
		  if(res == -1)
			  strcat(bufOut, "Тест не удалось запустить!");
		  *lenBufOut = strlen(bufOut);
	  }
	  else if (strncmp(tempValue, "\"time\"", 6) == 0){
		  valueLen = strpbrk(tempValue, ":");
		  strncpy(tempValue2, (valueLen+2), (strlen(valueLen)-2));
		  TimeParam = atoi(tempValue2);
		  res = ups_metac_service_pdu(ups_test_time);
		  if(res == 1 || res == 0){
			  strcat(bufOut, "Тест запущен!");
			  log_event_data(LOG_TEST_UPS, "Администратор (Запущен)");
		  }
		  if(res == -1)
			  strcat(bufOut, "Тест не удалось запустить!");
		  *lenBufOut = strlen(bufOut);
	  }
}

/**
  * @brief  Выклюение UPS
  */
void HTTP_UPSshutdown(char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut)
{
	  char *value = 0;
	  char *valueLen = 0;
	  char *valueLenEnd = 0;
	  char tempValue[50];
	  char tempValue2[50];
	  int8_t res = 0;

	  memset(tempValue, 0, 50);

	  strcpy(bufOut, HTTP_200_OK);

	  value = strstr(bufIn, "func");
	  valueLen = strpbrk(value, ":");
	  strncpy(tempValue, (valueLen+1), (strlen(valueLen)-2));
	  if (strcmp(tempValue, "\"cancel\"") == 0){
		  res = ups_metac_service_pdu(ups_cancel_shut_down);
		  if(res == 1){
			  log_event_data(LOG_SHUTDOWN_UPS, "Администратор(Останов)");
			  strcat(bufOut, "Выключение ИБП отменено!");
		  }
		  else
			  strcat(bufOut, "Выключение ИБП не удалось отменить!");
		  *lenBufOut = strlen(bufOut);
	  }
	  else if (strncmp(tempValue, "\"off\"", 5) == 0){
		  value = strstr(tempValue, "after");
		  valueLen = strpbrk(value, ":");
		  valueLenEnd = strpbrk(value, ",");
		  memset(tempValue2, 0, 50);
		  strncpy(tempValue2, (valueLen+2), (valueLenEnd - valueLen - 2));
		  TimeParam = atoi(tempValue2);
		  value = strstr(tempValue, "to");
		  valueLen = strpbrk(value, ":");
		  memset(tempValue2, 0, 50);
		  strncpy(tempValue2, (valueLen+2), (strlen(valueLen) - 2));
		  TimeParam2 = atoi(tempValue2);
		  res = ups_metac_service_pdu(ups_shutdown_restore);
		  if(res == 1){
			  strcat(bufOut, "Перезагрузка ИБП!");
			  log_event_data(LOG_SHUTDOWN_UPS, "Администратор");
		  }else
			  strcat(bufOut, "Отмена перезагрузки ИБП!");
		  *lenBufOut = strlen(bufOut);
	  }
}

/**
  * @brief  Проверка пароля для перехода в режим bootloader
  * @retval None
  */
void HTTP_ConfirmBootPwd(char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut)
{
  char tempStr[50];
  strncpy(tempStr, bufIn, 50);
  char value[20];
  uint8_t valueLen;
  
  memset(value, 0, 20);
  
  //if (GetParamValue(tempStr, "password=", value, &valueLen))
  {
	//if (strcmp(BOOTLOADER_PASWORD, value) == 0)
	{  
	 // *bufOut = '1';
	  /* Запускаем задачу отложенной перезагрузки. Контроллер должен успеть
       отправить ответ серверу о статусе пароля */
	  HTTP_StartResetTask(true); 
	}  
/*	else
	  *bufOut = '0';*/
	
	//*lenBufOut = 1;
  }
}

/**
  * @brief  Проверка пароля для входа в Web
  * @retval None
  */
int HTTP_ConfirmWebPwd(char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut)
{
	  char tempStr[50];
	  char login[20];
	  char password[20];
	  uint8_t valueLen, user_id;
	  char *strPtr = 0;
	  char WebPassword[MAX_WEB_PASSWD_LEN];
	  char WebLogin[MAX_WEB_LOGIN_LEN];
	  char buf[40];

	  memset(login, 0, 20);
	  memset(password, 0, 20);
	  memset(tempStr, 0, 50);

	  /* Get first 50 bytes of string */
	  strncpy(tempStr, bufIn, 49);

	  /* Add " " to the string in order GetParamValue() can be able to parse the param */
	  strcat(tempStr, " ");

	  if (GetParamValue(tempStr, "login=", login, &valueLen) &&
	      GetParamValue(tempStr, "password=", password, &valueLen))
	  {
	      for (user_id = 0; user_id < MAX_WEB_USERS; user_id++) {

	        GetUserLogin(user_id, WebLogin, &valueLen);
	        GetUserPassword(user_id, WebPassword, &valueLen);

	        /* Check login and password */
	        if ((strncmp(WebLogin, login, MAX_WEB_LOGIN_LEN) == 0) &&
	            (strncmp(WebPassword, password, MAX_WEB_PASSWD_LEN) == 0)) {

	            /* Login and pass are valid */

	            /* Check user's login session */
	            /* If "user" has logged in */
	            if (user_id >= 1) {

	            }

            /* TODO replace global flag with user-pass-cookie */
            Authenticated = true;

            /* Generate cookie */
            sprintf(tempStr, "%X", (unsigned int)GetRandomNumber());

            /* Set users cookie */
            HTTP_SetUserCookie(tempStr, user_id);

            HTTP_UpdateUserLoginTime(user_id);

            /* Send login and cookie back */
            strcpy(bufOut, "HTTP/1.0 200 OK\r\nContent-Type:text/html\r\nSet-Cookie: uname=");
            strcat(bufOut, WebLogin);
            strcat(bufOut, "\r\nSet-Cookie: id=");
            strcat(bufOut, tempStr);
            sprintf(tempStr, "%d", user_id);
            strcat(bufOut, "\r\nSet-Cookie: role=");
            strcat(bufOut, tempStr);
            strcat(bufOut, "\r\n\r\n");
            strcat(bufOut,"<!DOCTYPE html><html lang=""><head><meta http-equiv=\"refresh\" content=\"0;url=/index.html\"/></head></html>\r\n\r\n");

            *lenBufOut = strlen(bufOut);

            switch (user_id) {
                case 0:
                    snprintf(buf, sizeof(buf), "Администратор");
                    break;
                case 1:
                    snprintf(buf, sizeof(buf), "Пользователь");
                    break;
                default:
                    snprintf(buf, sizeof(buf), "", login);
                    break;
            }

            log_event_data(LOG_LOGIN, buf);
            /* Запускаем задачу-таймер логаута. */
            /* TODO отправить ответ серверу о статусе пароля */
            return SEND_REQUIRED_YES;
        }
        /*
        else {
            continue;
        }
        */
      }
    }
    /* No valid login and pass found */

    /* TODO replace global flag with user-pass-cookie*/
    Authenticated = false;
    /* Wrong login or pass, return */
    return SEND_REQUIRED_NO;
}

void HTTP_LOGIN(char *bufOut, uint16_t *lenBufOut)
{
	char tempStr[50];
	uint8_t valueLen;
	char WebLogin[MAX_WEB_LOGIN_LEN];

	GetUserLogin(ADMIN, WebLogin, &valueLen);

	memset(tempStr, 0, 50);

	/* TODO replace global flag with user-pass-cookie */
	Authenticated = true;

	/* Generate cookie */
	sprintf(tempStr, "%X", (unsigned int)GetRandomNumber());

	/* Set users cookie */
	HTTP_SetUserCookie(tempStr, ADMIN);

	HTTP_UpdateUserLoginTime(ADMIN);

	/* Send login and cookie back */
	strcpy(bufOut, "HTTP/1.0 200 OK\r\nContent-Type:text/html\r\nSet-Cookie: uname=");
	strcat(bufOut, WebLogin);
	strcat(bufOut, "\r\nSet-Cookie: id=");
	strcat(bufOut, tempStr);
	strcat(bufOut, "\r\nSet-Cookie: role=0");
	strcat(bufOut, "\r\nSet-Cookie: auth=0");
	strcat(bufOut, "\r\n\r\n");
	strcat(bufOut,"<!DOCTYPE html><html lang=""><head><meta http-equiv=\"refresh\" content=\"0;url=/index.html\"/></head></html>\r\n\r\n");

	*lenBufOut = strlen(bufOut);
}

/**
  * @brief  
  * @retval None
  */
uint8_t GetParamValue(char *inStr, char *paramName, char *paramValue, uint8_t *paramLen)
{
  char *beginValue = 0;
  char *endValue = 0;
  int  len = 0;
  char *strPtr = 0;
  
  strPtr = strstr(inStr, paramName);
  
  if (strPtr != 0)
  {
    beginValue = strpbrk(strPtr,"=");
    endValue = strpbrk(strPtr,"&");
    if (endValue == 0)
      endValue = strpbrk(strPtr," ");
    len = endValue - beginValue - 1;
    strncpy(paramValue, beginValue + 1, len);
    *endValue = '0';
    *beginValue = '0';
	*paramLen = len;
	return 1;
  }
  else
  {	
	*paramLen = 0;
	return 0;
  }
}

/**
  * @brief  
  * @retval None
  */
uint8_t GetCookieValue(char *inStr, char *paramName, char *paramValue, uint8_t *paramLen)
{
  char *beginValue = 0;
  char *endValue = 0;
  int  len = 0;
  char *strPtr = 0;

  strPtr = strstr(inStr, paramName);

  if (strPtr != 0)
  {
    beginValue = strpbrk(strPtr,"=");
    endValue = strpbrk(strPtr,";");
    if (endValue == 0)
      endValue = strpbrk(strPtr,"\n");
    len = endValue - beginValue - 1;
    strncpy(paramValue, beginValue + 1, len);
    *endValue = '0';
    *beginValue = '0';
    *paramLen = len;
    return 1;
  }
  else
  {
    *paramLen = 0;
    return 0;
  }
}

/**
  * @brief
  * @retval None
  */
/*
uint8_t GetParamValueInEnd(char *inStr, char *paramName, char *paramValue, uint8_t *paramLen)
{
  char *beginValue = 0;
  char *endValue = 0;
  int  len = 0;
  char *strPtr = 0;
  
  strPtr = strstr(inStr, paramName);
  
  if (strPtr != 0)
  {
    beginValue = strpbrk(strPtr,"=");
    endValue = strpbrk(strPtr," ");
    len = endValue - beginValue - 1;
    strncpy(paramValue, beginValue + 1, len);
    *endValue = '0';
    *beginValue = '0';
	*paramLen = len;
	return 1;
  }
  else
  {	
	*paramLen = 0;
	return 0;
  }
}
*/

void ClearParamString(char *inBuf)
{
  uint16_t len;
  char *str;
  
  str = strstr(inBuf, "HTTP");
  
  if (str != 0)
  {
    len = str - inBuf;
	memset(str, 0, RECIVE_BUF_MAX_LEN - len - 1);
  }
}

/**
  * @brief Чтение Cookie пользователя
  */
static void HTTP_GetUserCookie(uint8_t user_id, char *str, uint8_t *len)
{
    sprintf(str, "%s", users[user_id].cookie);
    *len = strlen(str);
}

/**
  * @brief Установка Cookie пользователя
  */
static void HTTP_SetUserCookie(char *str, uint8_t user_id)
{
    strcpy(users[user_id].cookie, str);
}

/**
  * @brief Обновление времени последней активности пользователя
  */
static void HTTP_UpdateUserLoginTime(uint8_t user_id)
{
    //xTimerStart(users[user_id].LogoutTimer, 0);
}

/**
  * @brief  Extract the Content_Length data from HTML data
  * @param  data : pointer on receive packet buffer
  * @param  len  : buffer length
  * @retval size : Content_length in numeric format
  */
static uint32_t Parse_Content_Length(char *data, uint32_t len)
{
  uint32_t i=0,size=0, S=1;
  int32_t j=0;
  char sizestring[6], *ptr;

  ContentLengthOffset =0;

  /* find Content-Length data in packet buffer */
  for (i=0;i<len;i++)
  {
    if (strncmp ((char*)(data+i), Content_Length, 16)==0)
    {
      ContentLengthOffset = i+16;
      break;
    }
  }
  /* read Content-Length value */
  if (ContentLengthOffset)
  {
    i=0;
    ptr = (char*)(data + ContentLengthOffset);
    while(*(ptr+i)!=0x0d)
    {
      sizestring[i] = *(ptr+i);
      i++;
      ContentLengthOffset++;
    }
    if (i>0)
    {
      /* transform string data into numeric format */
      for(j=i-1;j>=0;j--)
      {
        size += (sizestring[j]-0x30)*S;
        S=S*10;
      }
    }
  }
  return size;
}

/**
  * @brief Принудительный логаут пользователя
  */
static void HTTP_ForceUserLogout(uint8_t user_id)
{
    char cookie[MAX_WEB_COOKIE_LEN];

    /* Flush user cookie by random value */
    sprintf(cookie, "%X", (unsigned int)GetRandomNumber());
    HTTP_SetUserCookie(cookie, user_id);
}

/**
  * @brief >Callback таймера логаута пользователя
  */
void LogoutTimerCallback(TimerHandle_t pxTimer) {
    uint8_t user_id = (uint8_t)pvTimerGetTimerID( pxTimer );
	if( sSettings.sRADIUS.Auth_enable )
		HTTP_ForceUserLogout(user_id);
}

/**
  * @brief  Смена пароля пользователя
  * @retval None
  */
int HTTP_ChangeUserPwd(char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut)
{
    char tempStr[110];

    char value[20];
    char login[20];
    char password[20];
    uint8_t valueLen, valueLen2, user_id;
    char WebLogin[MAX_WEB_LOGIN_LEN];

    (void)lenBufIn;

    memset(login, 0, 20);
    memset(password, 0, 20);
    memset(tempStr, 0, 50);
    memset(value, 0, 20);

    ClearParamString(bufIn);

    strncpy(tempStr, bufIn, 110);

    strcpy(bufOut, HTTP_200_OK);

    if (GetParamValue(tempStr, "username=", login, &valueLen) &&
        GetParamValue(tempStr, "oldpass=", password, &valueLen))
    {
          for (user_id = 0; user_id < MAX_WEB_USERS; user_id++)
          {
        	  memset(value, 0, 20);
			  memset(WebLogin, 0, MAX_WEB_LOGIN_LEN);
			 GetUserLogin(user_id, WebLogin, &valueLen);
			 GetUserPassword(user_id, value, &valueLen2);
			 /* Check login and password */
			 if ((strncmp(WebLogin, login, MAX_WEB_LOGIN_LEN) == 0) &&
				 (memcmp(password, value, 11) == 0))
			 {
				 memset(password, 0, 20);
				 if (GetParamValue(tempStr, "newpass=", password, &valueLen))
				 {

					 memcpy(sSettings.sAuth[user_id].password, password, 11);

					 HTTP_SaveSettings();
					 log_event_data(LOG_PSW_CHANGE, "Администратор");
					 strcat(bufOut, "Пароль успешно изменён");
					 *lenBufOut = strlen(bufOut);
					 return SEND_REQUIRED_YES;
				 }
				 else {
					  strcat(bufOut, "Введены некорректные данные!");
					  *lenBufOut = strlen(bufOut);
					  return SEND_REQUIRED_YES;
				 }
			 }
          }
          strcat(bufOut, "Введён неверный пароль!");
          *lenBufOut = strlen(bufOut);
          return SEND_REQUIRED_YES;
  }
  else {
      strcat(bufOut, "Введены некорректные данные!");
      *lenBufOut = strlen(bufOut);
      return SEND_REQUIRED_YES;
  }
}
