//  This may look like C code, but it is really -*- C++ -*-

//  ------------------------------------------------------------------
//  The Goldware Library
//  Copyright (C) 1999 Alexander S. Aganichev
//  ------------------------------------------------------------------
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library 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
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library General Public
//  License along with this program; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
//  MA 02111-1307, USA
//  ------------------------------------------------------------------
//  $Id$
//  ------------------------------------------------------------------
//  Various WinOldAp functions.
//  ------------------------------------------------------------------

#include <cstdlib>
#include <cstdio>
#include <gstrall.h>
#include <gmemdbg.h>
#include <gutlos.h>
#include <gmemi86.h>
#ifdef __DJGPP__
#include <dos.h>
#include <unistd.h>
#include <dpmi.h>
#include <go32.h>
#include <sys/farptr.h>
#endif


//  ------------------------------------------------------------------

enum OSAPI {
  NOAPI,
  WIN3x,
  WIN9x,
  ANSIPLUS
};

OSAPI         winapi;
char          ge_win_oldtitle[GMAXTITLE+1] = "";
char          ge_win_title[GMAXTITLE+1] = "";
int           ge_win_ext_title;


//  ------------------------------------------------------------------

int g_init_os(int flags) {

  NW(flags);

  i86 cpu;

  // Identify WinOldAp version
  cpu.ax(0x1700);
  cpu.genint(0x2f);
  winapi = NOAPI;
  if(cpu.ax() != 0x1700) {
    winapi = WIN3x;
    // Identify Windows version and type
    cpu.ax(0x160a);
    cpu.genint(0x2f);
    if((cpu.ax() == 0x0000) and (cpu.bh() > 3))
      winapi = WIN9x;
  }
  else {
    // Check for ANSIPLUS.SYS v4.00+
    cpu.ax(0x1a00);
    cpu.bx(0x414e);
    cpu.cx(0x5349);
    cpu.dx(0x2b2b);
    cpu.genint(0x2f);
    if((cpu.al() == 0xff) and (cpu.ch() > 3))
      winapi = ANSIPLUS;
  }
  #if 0 // __DJGPP__: get djlocale patch instead
  // reload internal djgpp structures for toupper/tolower
  int segment, selector;

  if((segment = __dpmi_allocate_dos_memory(1, &selector)) != -1) {
    cpu.ah(0x65);
    cpu.al(0x02);
    cpu.bx(0xffff);
    cpu.dx(0xffff);
    cpu.cx(5);
    cpu.es(segment);
    cpu.di(0);
    cpu.genint(0x21);
    if(not (cpu.flags() & 1) and (cpu.cx() == 5)) {
      uint32_t table = _farpeekw(selector, 3) * 16 + _farpeekw(selector, 1);
      int i, size = _farpeekw(_dos_ds, table);
      movedata(_dos_ds, table + 2, _my_ds(), (uint32_t)&(toupper(128)), size);
      // let's build lowercase table from uppercase...
      for(i = 0; i < size; i++) {
        int c = toupper(i + 128);
        if((c != i + 128) and (c > 127))
          tolower(c) = i + 128;
      }
      for(i=128; i<256; i++) {
        if((toupper(tolower(i)) != i) and (tolower(toupper(i)) != i))
          tolower(i) = toupper(i) = i;
        if(toupper(tolower(i)) != toupper(i))
          toupper(i) = i;
        if(tolower(toupper(i)) != tolower(i))
          tolower(i) = i;
      }
    }
    __dpmi_free_dos_memory(selector);
  }
  #endif
  g_get_ostitle_name(ge_win_oldtitle);
  return 0;
}


//  ------------------------------------------------------------------

void g_deinit_os(void) {

  if(*ge_win_oldtitle)
    g_set_ostitle_name(ge_win_oldtitle, 1);
}


//  ------------------------------------------------------------------

void g_init_title(char *tasktitle, int titlestatus) {

  strxcpy(ge_win_title, tasktitle, GMAXTITLE);
  ge_win_ext_title = titlestatus;
}


//  ------------------------------------------------------------------

void g_increase_priority(void) {

  // Do nothing
}


//  ------------------------------------------------------------------

void g_set_ostitle(char* title, word dx) {

  if(winapi == WIN9x) {

    if(dx and not *title)
      return;

    i86 cpu;
    int segment, selector;
    size_t len = strlen(title) + 1;

    segment = __dpmi_allocate_dos_memory((len >> 4) + 1, &selector);
    if(segment == -1)
      return;
    movedata(_my_ds(), (unsigned)title, selector, 0, len);
    // Set application title
    cpu.ax(0x168e);
    cpu.dx(dx);
    cpu.es(segment);
    cpu.di(0x0000);
    cpu.genint(0x2f);
    __dpmi_yield();
    __dpmi_free_dos_memory(selector);
  }
}


//  ------------------------------------------------------------------

void g_set_osicon(void) {

  // do nothing
}


//  ------------------------------------------------------------------

bool g_is_clip_available(void) {

  return make_bool_not(winapi == NOAPI);
}


//  ------------------------------------------------------------------

char* g_get_clip_text(void) {

  if(winapi == NOAPI)
    return NULL;

  i86 cpu;
  int seg, selector;
  char* text = NULL;
  size_t len;

  if((winapi == WIN3x) or (winapi == WIN9x)) {

    // Open clipboard
    cpu.ax(0x1701);
    cpu.genint(0x2f);
    if(cpu.ax() == 0x0000)
      return NULL;

    // Get clipboard data size
    cpu.ax(0x1704);
    cpu.dx(0x07);
    cpu.genint(0x2f);
    len = cpu.ax() + (cpu.dx() << 16);
    if(len != 0)
      // For compatibility with http://www.chat.ru/~tulser/clipbrd.zip
      // we'll round up memory.
      if((seg = __dpmi_allocate_dos_memory((len + 0x1f) >> 4, &selector)) != -1) {
        // Get clipboard data
        cpu.ax(0x1705);
        cpu.dx(0x07); // OEM text
        cpu.es(seg);
        cpu.bx(0x0000);
        cpu.genint(0x2f);
        if(cpu.ax() != 0x0000) {
          text = (char *) throw_malloc(len+1);
          if(text)
            movedata(selector, 0, _my_ds(), (unsigned) text, len);
          text[len] = NUL;
        }
        __dpmi_free_dos_memory(selector);
      }

    // Close clipboard
    cpu.ax(0x1708);
    cpu.genint(0x2f);
  }
  else {
    // Get clipboard information
    cpu.ax(0x1aa5);
    cpu.dh(0x00);
    cpu.genint(0x2f);
    if(cpu.al() == 0x00) {
      len = cpu.cx();
      if(len)
        if((seg = __dpmi_allocate_dos_memory((len >> 4) + 1, &selector)) != -1) {
          // Get clipboard text
          cpu.ax(0x1aa5);
          cpu.dh(0x01);
          cpu.es(seg);
          cpu.bx(0x0000);
          cpu.genint(0x2f);
          if(cpu.al() == 0x00) {
            text = (char *) throw_malloc(len);
            if(text)
              movedata(selector, 0, _my_ds(), (unsigned) text, len);
          }
          __dpmi_free_dos_memory(selector);
        }
    }
  }

  return text;
}


//  ------------------------------------------------------------------

int g_put_clip_text(const char* buf) {

  if(winapi == NOAPI)
    return -1;

  i86 cpu;
  int seg, selector;
  int result = -1;
  size_t len = strlen(buf);

  if((winapi == WIN3x) or (winapi == WIN9x)) {
    // Open clipboard
    cpu.ax(0x1701);
    cpu.genint(0x2f);
    if(cpu.ax() == 0x0000)
      return -1;

    // Empty clipboard
    cpu.ax(0x1702);
    cpu.genint(0x2f);

    if(len>0) {
      if((seg = __dpmi_allocate_dos_memory((len >> 4) + 1, &selector)) != -1) {
        movedata(_my_ds(), (unsigned) buf, selector, 0, len);
        // Set clipboard data
        cpu.ax(0x1703);
        cpu.dx(0x07);
        cpu.si(len >> 16);
        cpu.cx(len & 0xffff);
        cpu.es(seg);
        cpu.bx(0);
        cpu.genint(0x2f);
        __dpmi_free_dos_memory(selector);
        if(cpu.ax() != 0x0000)
          result = 0;
      }
    }

    // Close clipboard
    cpu.ax(0x1708);
    cpu.genint(0x2f);
  }
  else {
    // Clear clipboard
    cpu.ax(0x1aa5);
    cpu.dh(0x04);
    cpu.genint(0x2f);
    if(len > 0)
      if((seg = __dpmi_allocate_dos_memory((len >> 4) + 1, &selector)) != -1) {
        movedata(_my_ds(), (unsigned) buf, selector, 0, len);
        // Set clipboard text
        cpu.ax(0x1aa5);
        cpu.dh(0x01);
        cpu.es(seg);
        cpu.bx(0x0000);
        cpu.cx(len & 0xffff);
        cpu.genint(0x2f);
        __dpmi_free_dos_memory(selector);
        if(cpu.al() == 0x00)
          result = 0;
      }
  }
  return result;
}


//  ------------------------------------------------------------------

void g_get_ostitle_name(char* title) {

  *title = NUL;
  if(winapi == WIN9x) {
    i86 cpu;
    int segment, selector;

    segment = __dpmi_allocate_dos_memory((GMAXTITLE >> 4) + 1, &selector);
    if(segment == -1)
      return;
    // Get vdm title
    cpu.ax(0x168e);
    cpu.dx(3);
    cpu.es(segment);
    cpu.di(0);
    cpu.cx(GMAXTITLE);
    cpu.genint(0x2f);
    movedata(selector, 0, _my_ds(), (unsigned)title, GMAXTITLE);
    strcat(title, " - ");
    int len = strlen(title);
    // Get application title
    cpu.ax(0x168e);
    cpu.dx(2);
    cpu.es(segment);
    cpu.di(0);
    cpu.cx(GMAXTITLE - len);
    cpu.genint(0x2f);
    movedata(selector, 0, _my_ds(), (unsigned)title + len, GMAXTITLE - len);
    __dpmi_free_dos_memory(selector);
    len = strlen(title);
    if(streql(title + len - 3, " - "))
      title[len-3] = NUL;
  }
}


//  ------------------------------------------------------------------

void g_set_ostitle_name(char* title, int mode) {

  if(mode == 0) {
    if(ge_win_ext_title)
      g_set_ostitle(title, 0);
  }
  else {
    char* p;
    char* s = throw_xstrdup(title);
    if((p = strstr(s, " - ")) != NULL) {
      *p = NUL;
      p += 3;
    }
    else
      p = s + strlen(s);
    g_set_ostitle(p, 0);
    g_set_ostitle(s, 1);
    throw_xfree(s);
  }
}


//  ------------------------------------------------------------------
