//------------------------------------------------------------------------------
// ZCPU standard library and drivers set              (C) 2011 by Black Phoenix
//
// UDH-enabled console screen highspeed driver
//------------------------------------------------------------------------------

//Define to check if console screen driver is available
#define CSCR_DRIVER

//Maximum number of console screens supported
#define MAX_CONSOLE_SCREENS 8

//Console screen registers
#define CURSOR_RATE       2043
#define CURSOR_SIZE       2044
#define CURSOR_POSITION   2045
#define CURSOR_VISIBLE    2046
#define LOW_SHIFT_COL     2031
#define HIGH_SHIFT_COL    2032
#define LOW_SHIFT_ROW     2033
#define HIGH_SHIFT_ROW    2034
#define SHIFT_ROWS        2038
#define SHIFT_CELLS       2037
#define CLEAR_SCREEN      2041
#define BACKGROUND_COLOR  2042
#define SCREEN_ACTIVE     2047
#define SCREEN_ROTATION   2024
#define SCREEN_BRIGHTNESS 2036

//Driver data
char* cscrOffsets[MAX_CONSOLE_SCREENS];
float cscrDevices[MAX_CONSOLE_SCREENS];
char* cscrCharacterPointer[MAX_CONSOLE_SCREENS];
float cscrSelectedScreen;

#ifdef UDH_DRIVER
//Update console screen offsets
void cscrUDHQueryFunction() {
  float i,n;
  n = udhGetDevices(11,MAX_CONSOLE_SCREENS,cscrDevices);
  for (i = 0; i < n; i++) {
    cscrOffsets[i] = udhGetDeviceOffset(cscrDevices[i]);
  }
}
#endif

//Initialize console screen driver. screenOffset may be 0 if using UDH
void cscrInitialize(char* screenOffset) {
  float i;

  for (i = 0; i < MAX_CONSOLE_SCREENS; i++) {
    cscrOffsets[i] = screenOffset;
  }

#ifdef UDH_DRIVER
    if (!screenOffset) {
      udhRegisterDriver(cscrUDHQueryFunction);
      cscrUDHQueryFunction();
    }
#endif
  cscrSelectedScreen = 0;
}

float cscrPresent(float screen) {
  return cscrOffsets[cscrSelectedScreen] != 0;
}

void cscrSelect(float screen) {
  cscrSelectedScreen = screen;
  max cscrSelectedScreen,0;
  min cscrSelectedScreen,MAX_CONSOLE_SCREENS;
}

void cscrSetActive(float clk) {
  if (!cscrOffsets[cscrSelectedScreen]) return;
  *(cscrOffsets[cscrSelectedScreen]+SCREEN_ACTIVE) = clk;
}

void cscrClear() {
  if (!cscrOffsets[cscrSelectedScreen]) return;
  *(cscrOffsets[cscrSelectedScreen]+CLEAR_SCREEN) = 1;
  cscrCharacterPointer[cscrSelectedScreen] = 0;
}

void cscrSetBackground(float col) {
  if (!cscrOffsets[cscrSelectedScreen]) return;
  *(cscrOffsets[cscrSelectedScreen]+BACKGROUND_COLOR) = col;
}

void cscrSetRotation(float rot) {
  *(cscrOffsets[cscrSelectedScreen]+SCREEN_ROTATION) = rot;
}

void cscrSetBrightness(float bright) {
  *(cscrOffsets[cscrSelectedScreen]+SCREEN_BRIGHTNESS) = bright;
}

void cscrLoadImage(char* imgdata) {
  if (!cscrOffsets[cscrSelectedScreen]) return;

  preserve ESI,EDI;
  ESI = imgdata;
  EDI = cscrOffsets[cscrSelectedScreen];
  mcopy 30*18*2;
}

void cscrPutLine(char* scrptr, float col, char* str) {
  if (!cscrOffsets[cscrSelectedScreen]) return;
  char* curptr = scrptr;

  while (*str) {
    *(cscrOffsets[cscrSelectedScreen]+curptr*2+0) = *str;
    *(cscrOffsets[cscrSelectedScreen]+curptr*2+1) = col;

    str++;
    curptr++;
  }
}

void cscrPutChar(char* scrptr, float col, char ch) {
  if (!cscrOffsets[cscrSelectedScreen]) return;

  *(cscrOffsets[cscrSelectedScreen]+scrptr*2+0) = ch;
  *(cscrOffsets[cscrSelectedScreen]+scrptr*2+1) = col;
}

void cscrNewLine() {
  if (!cscrOffsets[cscrSelectedScreen]) return;

  cscrCharacterPointer[cscrSelectedScreen] /= 30;
  fint cscrCharacterPointer[cscrSelectedScreen];
  cscrCharacterPointer[cscrSelectedScreen] = (cscrCharacterPointer[cscrSelectedScreen]+1)*30;

  if (cscrCharacterPointer[cscrSelectedScreen] >= 30*18) {
    cscrCharacterPointer[cscrSelectedScreen] = cscrCharacterPointer[cscrSelectedScreen] - 30;
    *(cscrOffsets[cscrSelectedScreen]+SHIFT_ROWS) = 1;
  }
}

void cscrPrintLine(char* str, float col) {
  if (!cscrOffsets[cscrSelectedScreen]) return;

  while (*str) {
    if (*str == '\n') {
      cscrNewLine();
      str++;
      if (*str == 0) return;
    }

    *(cscrOffsets[cscrSelectedScreen]+cscrCharacterPointer[cscrSelectedScreen]*2+0) = *str;
    *(cscrOffsets[cscrSelectedScreen]+cscrCharacterPointer[cscrSelectedScreen]*2+1) = col;

    cscrCharacterPointer[cscrSelectedScreen]++;
    if (cscrCharacterPointer[cscrSelectedScreen] >= 30*18) cscrNewLine();
    str++;
  }
}

void cscrPrintNumber(float num, float col) {
  if (!cscrOffsets[cscrSelectedScreen]) return;

  float ndig,a;
  a = num;
  ndig = 0;
  while (a > 0) {
    ndig++;
    a /= 10;
    fint a;
  }
  max ndig,1;
  a = num;

  cscrCharacterPointer[cscrSelectedScreen] = cscrCharacterPointer[cscrSelectedScreen] + ndig;
  char* charPtr = cscrCharacterPointer[cscrSelectedScreen] - 1;
  while (ndig > 0) {
    preserve EDX;
    mov EDX,a;
    mod EDX,10;
    add EDX,48;

    *(cscrOffsets[cscrSelectedScreen]+charPtr*2+0) = EDX;
    *(cscrOffsets[cscrSelectedScreen]+charPtr*2+1) = col;
    charPtr--;

    a /= 10;
    fint a;

    ndig--;
  }
}

void cscrSetCursor(float x, y) {
  if (!cscrOffsets[cscrSelectedScreen]) return;
  cscrCharacterPointer[cscrSelectedScreen] = x+y*30;
}
