/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <pspwlan.h>
#include <pspkernel.h>
#include <psppower.h>
#include <pspctrl.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <SDL.h>

#include "psp_global.h"
#include "psp_nlh.h"
#include "psp_sdl.h"
#include "psp_menu.h"

#define MAX_PICK 5
#define MAX_PICK_TITLE 80
#define MAX_PICK_MAINSTR 13
#define MAX_PICK_FINEPRINT 45

typedef struct
{
    char szBig[MAX_PICK_MAINSTR+1]; // big font
    char szFinePrint[MAX_PICK_FINEPRINT+1]; // small font
    u32 userData;
} PICKER_INFO;

typedef struct
{
    int         pick_count;
    PICKER_INFO picks[MAX_PICK];
    int         pick_start; // -1 for none, 0->pick_count-1 for selection

} PICKER;

void 
my_initpicker(PICKER* pickerP)
{
  pickerP->pick_count = 0;
  pickerP->pick_start = -1;
}

int 
my_addpick(PICKER* pickerP, const char* szBig, const char* szFinePrint, u32 userData)
{
    PICKER_INFO* pickP;
    if (pickerP->pick_count >= MAX_PICK)
        return 0; // no room
        // REVIEW: in future provide a smaller font version with more slots
    pickP = &(pickerP->picks[pickerP->pick_count++]);

    strncpy(pickP->szBig, szBig, MAX_PICK_MAINSTR);
    pickP->szBig[MAX_PICK_MAINSTR] = '\0';
    if (szFinePrint == NULL)
        szFinePrint = "";
    strncpy(pickP->szFinePrint, szFinePrint, MAX_PICK_FINEPRINT);
    pickP->szFinePrint[MAX_PICK_FINEPRINT] = '\0';
    pickP->userData = userData;
    return 1;
}

static void
psp_wifi_display_screen()
{
  psp_sdl_blit_wifi();

  psp_sdl_draw_rectangle(10,10,459,249,PSP_MENU_BORDER_COLOR,0);
  psp_sdl_draw_rectangle(11,11,457,247,PSP_MENU_BORDER_COLOR,0);

  psp_sdl_back_print( 30, 6, " Wifi connection ", PSP_MENU_NOTE_COLOR);

  psp_display_screen_menu_battery();

  psp_sdl_back_print(30, 254, " []: Cancel  O/X: Valid  ", 
                     PSP_MENU_BORDER_COLOR);

  psp_sdl_back_print(370, 254, " By Zx-81 ",
                     PSP_MENU_AUTHOR_COLOR);
}


#define Y_PICK(i)    (4+3*(i))
#define X_PICK       (8)
#define STR_PICK "=>"

void
my_psp_sdl_back_print(int x, int y, char *text, int color)
{
  psp_sdl_back_print(x * 8, y * 8, text, color);
}

int
my_picker(const PICKER* pickerP)
{
    int iPick = pickerP->pick_start;
    u32 buttonsLast = 0;
    int bRedraw = 1;

    if (pickerP->pick_count == 0) {
        return -1; // nothing to pick
    }

    while (1)
    {
      int i;
      SceCtrlData pad;
      u32 buttonsNew;

# if 0 //LUDO:
      if (pickerP->pick_count == 1) {
        // auto-pick if only one
        iPick = 0;
        break;
      }
# endif

      if (bRedraw) {
        psp_wifi_display_screen();

        for (i = 0; i < pickerP->pick_count; i++)
        {
          PICKER_INFO const* pickP = &pickerP->picks[i];
          int text_color = PSP_MENU_TEXT_COLOR;
          if (i == iPick)
          {
            text_color = PSP_MENU_SEL_COLOR;
            my_psp_sdl_back_print(4, Y_PICK(i), STR_PICK, text_color);
          }
          my_psp_sdl_back_print(X_PICK, Y_PICK(i), pickP->szBig, text_color);
          my_psp_sdl_back_print(X_PICK + 2, Y_PICK(i) + 1, pickP->szFinePrint, text_color);
        }
        bRedraw = 0;
        psp_sdl_flip();
      }

      // handle up/down inputs
      sceCtrlReadBufferPositive(&pad, 1); 
      buttonsNew = pad.Buttons & ~buttonsLast;
      buttonsLast = pad.Buttons;

      if (buttonsNew & PSP_CTRL_DOWN) {
        iPick++;
        if (iPick >= pickerP->pick_count)
            iPick = pickerP->pick_count-1;
        bRedraw = 1;
      }
      else if (buttonsNew & PSP_CTRL_UP) {
        iPick--;
        if (iPick < 0) iPick = 0;
        bRedraw = 1;
      }
      else if (buttonsNew & (PSP_CTRL_CIRCLE | PSP_CTRL_CROSS)) {
        if (iPick >= 0 && iPick < pickerP->pick_count) {
              break; // picked !
        }
      }
      else if (buttonsNew & PSP_CTRL_SQUARE)
      {
        iPick = -1; // cancel
        break;
      }
    }
    return iPick;
}

int 
psp_wifi_connect()
{
  int last_state;
  u32 err;
  char szMyIPAddr[32];
  int connectionConfig = -1;
  PICKER pickConn; // connection picker
  int iNetIndex;
  int iPick;

  psp_wifi_display_screen();
  psp_sdl_flip();

  // nlhInit must be called from user thread for DHCP to work
  err = nlhInit();

  if (err != 0) {
    pspDebugScreenPrintf("nlhInit: %d !\n", err);
    nlhTerm();
    return;
  }

  while (sceWlanGetSwitchState() != 1)  //switch = off
  {
    psp_wifi_display_screen();
    my_psp_sdl_back_print(4, 4, "Turn the wifi switch on !", PSP_MENU_RED_COLOR);
    psp_sdl_flip();
    sceKernelDelayThread(1000*1000);
  }

  // enumerate connections
  my_initpicker(&pickConn);

  for (iNetIndex = 1; iNetIndex < 100; iNetIndex++) // skip the 0th connection
  {
    char data[128];
    char name[128];
    char detail[128];
    if (sceUtilityCheckNetParam(iNetIndex) != 0) continue;
    sceUtilityGetNetParam(iNetIndex, 0, name);

    sceUtilityGetNetParam(iNetIndex, 1, data);
    strcpy(detail, "SSID=");
    strcat(detail, data);

    sceUtilityGetNetParam(iNetIndex, 4, data);
    if (data[0]) {
      // not DHCP
      sceUtilityGetNetParam(iNetIndex, 5, data);
      strcat(detail, " IPADDR=");
      strcat(detail, data);
    } else {
      strcat(detail, " DHCP");
    }

    my_addpick(&pickConn, name, detail, (u32)iNetIndex);
    if (pickConn.pick_count >= MAX_PICK) break;  // no more
  }

  if (pickConn.pick_count == 0) {
    psp_wifi_display_screen();
    my_psp_sdl_back_print(4,4, "No wifi connection, please create one !", PSP_MENU_TEXT_COLOR);
    psp_sdl_flip();
    goto close_net;
  }

  pickConn.pick_start = 0;
  iPick = my_picker(&pickConn);
  if (iPick == -1) goto close_net;
  connectionConfig = (int)(pickConn.picks[iPick].userData);

connect_wifi:

  err = sceNetApctlConnect(connectionConfig);
  if (err != 0) {
    goto close_net;
  }

  {
    char buffer[128];
    psp_wifi_display_screen();
    strcpy(buffer, "Trying to connect to ");
    strcat(buffer, pickConn.picks[iPick].szBig);
    my_psp_sdl_back_print(4, 4, buffer, PSP_MENU_TEXT_COLOR);
    psp_sdl_flip();
  }

  // 4 connected with IP address
  
  last_state = -1;

  while (1) 
  {
    int state = 0;
    char buffer[128];

    sceKernelDelayThread(50*1000);
    err = sceNetApctlGetState(&state);

    if (err != 0)
    {
      psp_wifi_display_screen();
      my_psp_sdl_back_print(4, 4, "Connection failed !", PSP_MENU_TEXT_COLOR);
      psp_sdl_flip();
      
      goto close_connection;
    }

    {
      SceCtrlData c;
      sceCtrlReadBufferPositive(&c, 1);
      if (c.Buttons & PSP_CTRL_SQUARE) goto close_connection;
    }

    if (state != last_state) 
    {
      if (last_state == 2 && state == 0)
      {
        psp_wifi_display_screen();
        my_psp_sdl_back_print(4, 4, "Connecting to wifi Failed, Retrying...", PSP_MENU_TEXT_COLOR);
        psp_sdl_flip();

        sceKernelDelayThread(500*1000); // 500ms
        goto connect_wifi;
      }
     
      psp_wifi_display_screen();
      sprintf(buffer, "Connection state %d of 4", state);
      my_psp_sdl_back_print(4, 4, buffer, PSP_MENU_TEXT_COLOR);
      psp_sdl_flip();

      last_state = state;
    }

    // 0 - idle
    // 1,2 - starting up
    // 3 - waiting for dynamic IP
    // 4 - got IP - usable
    if (state == 4) break;  // connected with static IP
  }

  // get IP address
  if (sceNetApctlGetInfo(8, szMyIPAddr) != 0) {
    strcpy(szMyIPAddr, "unknown IP address");
  }

  /* Let's go to login menu now */
  psp_login_menu();

close_connection:
  err = sceNetApctlDisconnect();

close_net:
  psp_wifi_display_screen();
  my_psp_sdl_back_print(4, 4, "Closing connection ...", PSP_MENU_TEXT_COLOR);
  psp_sdl_flip();
  
  nlhTerm();
  sceKernelDelayThread(1000000); 
}
