/*
 *  suse-blinux - Braille-display support for linux
 *  Author: Marco Skambraks <marco@suse.de>
 *  SuSE GmbH Nuernberg
 *
 *
 * suse-blinux based on brltty
 * special thanks to the Brltty-Team
 * Nicolas Pitre <nico@cam.org>
 * Stphane Doyon <s.doyon@videotron.ca>
 * Nikhil Nair <nn201@cus.cam.ac.uk>
 *
 * This is free software, placed under the terms of the
 * GNU General Public License, as published by the Free Software
 * Foundation.  Please see the file COPYING for details.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include "../cmdkeys.h"
#include "../trans.h"
#include "variolow.h"
#include "../brl.h"
#include "../brl_driver.h"
#include "../sbllog.h"
#include "../inskey.h"

#define MAXCNT 150
#define CHKREAD 1
#define KEYTBL "/german"
#define CMDTBL "/cmdtbl"

static int fakecnt=0;
extern void resetbrl();
int keytbl(int ch);
int insert(char ch,int cmd);
void loadcmdkeys();
void loadkeytbl();
static unsigned char txttrans[256];
static unsigned char lastbuff[84];


/* extern int DEBUG; */
extern unsigned char st_disp[4];
struct brlinfo htdevs[] = {
  {"ht40", "Handy-Tech 40", 40, 4, 0, 0, B19200},
  {"ht80", "Handy-Tech 80", 80, 4, 0, 0, B19200},
  {"brlwave", "Handy-Tech Braille-Wave", 40, 0, 0, 0, B19200},
  {"vario40-ht", "Baum Vario40 via Handy-Tech emu", 40, 4, 0, 0, B19200},
  {"vario80-ht", "Baum Vario80 via Handy-Tech emu", 80, 4, 0, 0, B19200},
  {"dm80p-ht", "Baum DM80Plus via Handy-Tech emu", 80, 4, 0, 0, B19200},
    {"brlstar40", "Handy-Tech Braille-Star 40", 40, 0, 0, 0, B19200}
};


#define HT40 0
#define HT80 1
#define BRLWAVE 2
#define BRLSTAR40 6
int devnr = 0;

struct brlinfo identbrl (const char *name, const char *dev)
{

  int devcnt;
  struct brlinfo retinfo;

  devcnt = sizeof (htdevs) / sizeof (struct brlinfo);
  retinfo.cols = 0;
  for (devnr = 0; devnr < devcnt; devnr++)
    if (!strcmp (name, htdevs[devnr].name))
     {
       printf ("Using: %s on %s\n", htdevs[devnr].fullname, dev);
       retinfo = htdevs[devnr];
       break;
     }

  return retinfo;
}

void initbrl (brldim * brl, const char *dev)
{

  /*      Seems to signal en error */
  if(devnr==2)
  {
   loadcmdkeys();
   loadkeytbl();
   }
   
  brl->x = -1;
  if (!varioinit ((char *) dev))
   {
     brl->x = BRLCOLS;
     {
       sbl_log ("devnr: %i cols: %i \n", devnr, htdevs[devnr].cols);
     }
     brl->y = 1;
     if (!(brl->disp = malloc (brl->x * brl->y)))
      {
	perror (dev);
	brl->x = -1;
      }
   }
}

void closebrl (brldim * brl)
{
  varioclose ();
  free (brl->disp);
}

void writebrl (brldim * brl)
{
  char outbuff[BRLCOLS];
  int i;

  /*      Idiot check one */
  if (!brl || !brl->disp)
   {
     return;
   }
  /*      Only display something if the data actually differs, this 
   *      could most likely cause some problems in redraw situations etc
   *      but since the darn thing wants to redraw quite frequently otherwise 
   *      this still makes a better lookin result */
  for (i = 0; i < BRLCOLS; i++)
   {
     if (lastbuff[i] != brl->disp[i])
      {
	memcpy (lastbuff, brl->disp, BRLCOLS * sizeof (char));

	/*      Redefine the given dot-pattern to match ours */
	variotranslate (brl->disp, outbuff, BRLCOLS);
	variodisplay (outbuff);
	break;
      }
   }
}

void setbrlstat (const unsigned char *st)
{
const char lowbits[10] = { 64 | 128 | 32, 4, 4 | 64, 4 | 32, 4 | 32 | 128,
  4 | 128, 4 | 64 | 32, 4 | 64 | 32 | 128, 4 | 64 | 128, 64 | 32
};
const char highbits[10] = { 2 | 8 | 16, 1, 1 | 2, 1 | 8, 1 | 8 | 16, 1 | 16, 1 | 2 | 8, 1 | 2 | 8 | 16, 1 | 2 | 16, 2 | 8 };

  st_disp[0] = highbits[st[0] / 10] | lowbits[st[1] / 10];
  st_disp[1] = highbits[st[0] % 10] | lowbits[st[1] % 10];
  st_disp[2] = highbits[st[2] / 10];
  st_disp[3] = highbits[st[2] % 10];

/* variotranslate(st_disp,st,ST_MODULES); */
}

int readbrl (int *type)
{
static int kbdmode=0;
static int space=0;
  int c;

  /*      Since we are nonblocking this will happen quite a lot */
  if ((c = varioget ()) == -1)
  {
  fakecnt++;
  if(fakecnt>MAXCNT)
  {
  sbl_log("1. try to reset");
  resetbrl();
  fakecnt=0;
   return EOF;
   }
   return EOF;
   }
   
   
   
   
   if(c==VARIO_DISPLAY_DATA_ACK)
   {
   fakecnt=0;
   return EOF;
   }
   else
   {
   fakecnt++;
   sbl_log("fakecnt=%d\n",fakecnt);
   if(fakecnt>MAXCNT)
   {
   sbl_log("try to resetbrl\n");
   resetbrl();
   fakecnt=0;
   return EOF;
   }
   }
   

  if (c >= 0x20 && c <= 0x6f)
   {
     *type = 1;
     return c - 0x20 + 104;
   }
   
   
   if(kbdmode)
   {
	switch(c)
	{
	case B05_PRESS:
	*type=1;
	return 5;
	
	case B05_REL:
	*type=0;
	return 5;
	
	case B06_PRESS:
	*type=1;
	return 6;
	
	case B06_REL:
	*type=0;
	return 6;
	default:
   kbdmode=keytbl(c);
   return EOF;
    } /* switch */
   } /* if */


   if(space)
   {
   if(c==0x90) space=0;
   if(c==0xc) 
   {
   space=0;
   kbdmode=1;
   }
    return EOF;
    }
   
   
   
  switch (c)
   {
/*   case 0xc: 
   if(devnr==BRLWAV)
   {
   inskey(
   return EOF;
   }
   break;
   */
   case 0x10:
   if(devnr==BRLWAVE)
   {
   space=1;
   return EOF;
   }
   if(devnr==BRLSTAR40)
   {
   *type=1;
   return 5;
   }
   case 0x90:
   if(devnr==BRLWAVE)
   {
   space=0;
   return EOF;
   }
   if(devnr==BRLSTAR40)
   {
   *type=0;
   return 5;
   }
   case VARIO_DISPLAY_DATA_ACK:
     return EOF;
   case B01_PRESS:
     *type = 1;
     return 1;
   case B01_REL:
     *type = 0;
     return 1;
   case B02_PRESS:
     *type = 1;
     return 2;
   case B02_REL:
     *type = 0;
     return 2;
   case B03_PRESS:
     *type = 1;
     return 3;
   case B03_REL:
     *type = 0;
     return 3;
   case B04_PRESS:
     *type = 1;
     return 4;

   case B04_REL:
     *type = 0;
     return 4;
   case B05_PRESS:
     *type = 1;
     if(devnr==BRLSTAR40) return 13;
     return 5;
   case B05_REL:
     *type = 0;
     if(devnr==BRLSTAR40) return 13;
     return 5;
   case B06_PRESS:
     *type = 1;
     if(devnr==BRLSTAR40) return 14;
     return 6;
   case B06_REL:
     *type = 0;
     if(devnr==BRLSTAR40) return 14;
     return 6;
   case B07_PRESS:
     *type = 1;
     return 7;
   case B07_REL:
     *type = 0;
     return 7;
   case B08_PRESS:
     *type = 1;
     return 8;
   case B08_REL:
     *type = 0;
     return 8;
   case B09_PRESS:
     *type = 1;
     return 9;
   case B09_REL:
     *type = 0;
     return 9;
   case B10_PRESS:
     *type = 1;
     return 10;
   case B10_REL:
     *type = 0;
     return 10;

     /* numpad B9 - b14 */
   case 0x12:
     *type = 1;
     return 11;
   case 0x92:
     *type = 0;
     return 11;
   case 0x02:
     *type = 1;
     return 12;
   case 0x82:
     *type = 0;
     return 12;
   case 0x11:
     *type = 1;
     return 13;
   case 0x91:
     *type = 0;
     return 13;
   case 0x01:
     *type = 1;
     return 14;
   case 0x81:
     *type = 0;
     return 14;
   case 0x09:
     *type = 1;
     return 15;
   case 0x89:
     *type = 0;
     return 15;
   case 0x0d:
     *type = 1;
     return 16;
   case 0x8d:
     *type = 0;
     return 16;

     /* numpad 0 -9 */
   case 0x05:
     *type = 1;
     return 20;
   case 0x85:
     *type = 0;
     return 20;
   case 0x15:
     *type = 1;
     return 21;
   case 0x95:
     *type = 0;
     return 21;
   case 0x19:
     *type = 1;
     return 22;
   case 0x99:
     *type = 0;
     return 22;
   case 0x1d:
     *type = 1;
     return 23;
   case 0x9d:
     *type = 0;
     return 23;
   case 0x06:
     *type = 1;
     return 24;
   case 0x86:
     *type = 0;
     return 24;
   case 0x0a:
     *type = 1;
     return 25;
   case 0x8a:
     *type = 0;
     return 25;
   case 0x0e:
     *type = 1;
     return 26;
   case 0x8e:
     *type = 0;
     return 26;
   case 0x16:
     *type = 1;
     return 27;
   case 0x96:
     *type = 0;
     return 27;
   case 0x1a:
     *type = 1;
     return 28;
   case 0x9a:
     *type = 0;
     return 28;
   case 0x1e:
     *type = 1;
     return 29;
   case 0x9e:
     *type = 0;
     return 29;

   case 12:
   if(devnr==BRLSTAR40 || devnr==BRLWAVE) 
   {
   *type=1;
   return 11;
   }
   break;
   case 140:
   if(devnr==BRLSTAR40 || devnr==BRLWAVE) 
   {
   *type=0;
   return 11;
   }
   break;
   case 20:
   if(devnr==BRLSTAR40 || devnr==BRLWAVE) 
   {
   *type=1;
   return 12;
   }
   break;
   case 148:
   if(devnr==BRLSTAR40 || devnr==BRLWAVE) 
   {
   *type=0;
   return 12;
   }
   break;
  
   case 24:
   *type=1;
        if(devnr==BRLSTAR40) return 6;
        break;
        case 152:
        *type=0;
             if(devnr==BRLSTAR40) return 6;
             break;
   default:
     /* statuscell routing keys */
     if (c >= 0x70 && c <= 0x73)
      {
	*type = 1;
	return c - 0x70 + 100;
      }

     *type = 0;
     return EOF;

   }
}

int keytbl(int ch)
{
static int pressed_keys=0;
static char insch=0;
static int space=0;
static was_cmd=0;


switch(ch)
{
case 20:
inskey("\r");
break;
 case 0x10: /* space bar */
 space=1;
/*  pressed_keys++; */
 break;
 case 0xf: /* dot 1 */
 insch|=1;
 pressed_keys++;
 break;

 case 0xb: /* dot 2 */
 insch|=2;
 pressed_keys++;
 break;
 case 0x7: /* dot 3 */
 insch|=4;
 pressed_keys++;
 break;
 case 0x13: /* dot 4 */
 insch|=8;
 pressed_keys++;
 break;
 case 0x17: /* dot 5 */
 insch|=16;
 pressed_keys++;
 break;
 case 0x1b: /* dot 6 */
 insch|=32;
 pressed_keys++;
 break;
 case 0x3: /* dot 7 */
 insch|=64;
 pressed_keys++;
 break;
 case 0x1f: /* dot 8 */
 insch|=128;
 pressed_keys++;
 break;
/* key release */
 case 0x90: /* space release */
 if(was_cmd) was_cmd=0;
 else
 if(space)
 inskey(" ");
space=0;
 break;
 case 0x8f: case 0x9f: case 0x8b: case 0x87: case 0x93:
 case 0x97: case 0x83: case 0x9b:
 if(pressed_keys)
 {
was_cmd=1;
 sbl_log("pressed_keys = %d ",pressed_keys);
  pressed_keys--;
  if(!pressed_keys)
  {
   sbl_log("start insert ");
   insert(insch,space);
   insch=0;
/*   space=0; */
   }
   
   }
   
   break;
 case 0xc: /* exit kbdmode */
 sbl_log("exit kbdmode ");
 return 0;
 }
 
 return 1;
 
}
 
 
 
 
int insert(char ch,int cmd)
{


char str[10]="";

sprintf(str,"%c",(char)txttrans[(int)ch]);
if(cmd)
{
int i=0;
if(ch==0)
inskey(" ");
else
do
{
if(inscmd[i].brlkey==(int)ch)
{
inskey(inscmd[i].instr);
break;
}
i++;
}
while(inscmd[i].brlkey!=-1);

}
else
inskey(str);

return 0;
}

void loadkeytbl()
{
int tbl_fd=0;
 if ((tbl_fd = open (KEYTBL, O_RDONLY)) >= 0
                    && (read (tbl_fd, txttrans, 256) == 256))
                    sbl_log("keytable loaded\n");
                    else
                    sbl_log("eroor: loading keytable\n");
}

void loadcmdkeys()
{

#define GETVAL(string) bintrans(vecsearch(strcpy(str,string)))
char str[20];

iniread(CMDTBL);


inscmd[0].brlkey=GETVAL("csrdn");
inscmd[1].brlkey=GETVAL("csrup");
inscmd[2].brlkey=GETVAL("csrlft");
inscmd[3].brlkey=GETVAL("csrrgt");
inscmd[4].brlkey=GETVAL("esc");
inscmd[5].brlkey=GETVAL("ctrla");
inscmd[6].brlkey=GETVAL("ctrlc");
inscmd[7].brlkey=GETVAL("ctrld");
inscmd[8].brlkey=GETVAL("ctrle");
inscmd[9].brlkey=GETVAL("ctrlz");
inscmd[10].brlkey=GETVAL("tab");
inscmd[11].brlkey=GETVAL("del");
inscmd[12].brlkey=GETVAL("backspace");
inscmd[13].brlkey=GETVAL("insert");
inscmd[14].brlkey=GETVAL("home");
inscmd[15].brlkey=GETVAL("end");
inscmd[16].brlkey=GETVAL("pgup");
inscmd[17].brlkey=GETVAL("pgdn");
inscmd[18].brlkey=GETVAL("f1");
inscmd[19].brlkey=GETVAL("f10");

}