/* =========================================================== */
/*                 Bink/+ Clock Screen Saver                   */
/*                  crossplatformed version                    */
/*          Created by CAE (aka Sergey A. Eremenko)            */
/* =========================================================== */

/* =========================================================== */
/* now compiled under next OSes and "OS"es :                   */
/*   MSDOS by Watcom                                           */
/*   Windows 3.1 by Watcom                                     */
/*   Windows 95/NT (Win32) by Watcom                           */
/*   FreeBSD by GCC  ;((((                                     */
/*   OS/2 by GCC for Brake!                                    */
/* =========================================================== */

/* =========================================================== */
/*                Declaration for all OSes                     */
/* =========================================================== */

#include <stddef.h>
#include <stdlib.h>
#include <fcntl.h>

#ifndef __IBMC__
#ifndef __IBMCPP__
#include <unistd.h>
#endif
#endif

#include <time.h>

/*#define TEST*/

static char program_name[] = "\r\n\r\nSCRNSAVE: Bink/+ Clock\r\n\r\n" ;
static char address[] = "2:5061/32.46" ;

static char big_numbers[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f} ;
static int Mikel ;
static int Cae ;
static int minute = -1, hour = -1 ;
static int maxx,maxy,sqx,sqy ;

#define VERTICAL_BAR_866        (unsigned char)'\xb3'
#define HORIZONTAL_BAR_866      (unsigned char)'\xc4'
#define MAX_STRING              255

/* ----------------------------------------------------------- */
/* set_new_random - set new point for pseudo random numbers    */
/* ----------------------------------------------------------- */

static void set_new_random ( void ) {
  srand ((unsigned)time (NULL)) ;
}

/* ----------------------------------------------------------- */
/* get_random - get pseudo random number - from 0 to max       */
/* ----------------------------------------------------------- */

static int get_random (int max) {
  return rand () % max ;
}

/* ----------------------------------------------------------- */
/* setup_colors - setup Mikel and Cae variables                */
/* ----------------------------------------------------------- */

static void setup_colors (void) {
  Mikel = 0 ;
  Cae = 0 ;
/*  if ((Mikel = open ("/mikel",O_RDONLY))>=0) {
    close (Mikel) ;
    Mikel = 1 ;
  }
  else {
    Mikel = 0 ;
  }
  if ((Cae = open (&address[6],O_RDONLY))>=0) {
    close (Cae) ;
    Cae = 1 ;
  }
  else {
    Cae = 0 ;
  }*/
}

/* ----------------------------------------------------------- */
/* new_minute - true if new minute setted, false else          */
/* ----------------------------------------------------------- */

static int new_minute (void) {
  time_t t ;
  struct tm * tt ;

  time (&t) ;
  tt = localtime (&t) ;
  if (tt->tm_hour!=hour || tt->tm_min!=minute) {
    hour = tt->tm_hour ;
    minute = tt->tm_min ;
    return 1 ;
  }
  return 0 ;
}

/* =========================================================== */
/*               Declaration for text screens                  */
/* =========================================================== */

#define VERTICAL_BAR    VERTICAL_BAR_866
#define HORIZONTAL_BAR  HORIZONTAL_BAR_866

#define ZHUZHKA '\x04'

#define INCL_DOS
#define INCL_KBD
#define INCL_VIO
#include <os2.h>

#ifndef __IBMC__
#define __cdecl _Cdecl
#endif

struct scp {
  int xmax ;
  int ymax ;
} ;

static int scr_blanked ;

static void fillh (int x, int y, unsigned short a, int len) {
  int i ;

  for (i=0 ; i<len ; i++)
    VioWrtNCell ((PCH)&a,1,y+i,x,0) ;
}

static void fillw (int x, int y, unsigned short a, int len) {
  VioWrtNCell ((PCH)&a,len,y,x,0) ;
}

static void print_number (int x,int y,char numb,int color) {
  unsigned short h = color|HORIZONTAL_BAR ;
  unsigned short v = color|VERTICAL_BAR ;

  numb = big_numbers[numb] ;
  if (numb&0x01) fillw (x+1,y,h,sqx) ;
  if (numb&0x02) fillh (x+sqx+1,y+1,v,sqy) ;
  if (numb&0x04) fillh (x+sqx+1,y+sqy+2,v,sqy) ;
  if (numb&0x08) fillw (x+1,y+sqy*2+2,h,sqx) ;
  if (numb&0x10) fillh (x,y+sqy+2,v,sqy) ;
  if (numb&0x20) fillh (x,y+1,v,sqy) ;
  if (numb&0x40) fillw (x+1,y+sqy+1,h,sqx) ;
}

static void print_time (void) {
  int x1,y1 ;
  int color ;

  if (Mikel) {
    color = 0x200 ;
  }
  else {
    while ((color=get_random (8))==0) ;
    color <<= 8 ;
  }
  fillw (0,0,color|' ',maxx*maxy) ;
  x1 = get_random (maxx-4*(sqx+2)-5) ;
  y1 = get_random (maxy-2*(sqy+2)) ;
  print_number (x1,y1,hour/10,color) ;
  print_number (x1+=sqx+3,y1,hour%10,color) ;
  print_number (x1+=sqx+5,y1,minute/10,color) ;
  print_number (x1+=sqx+3,y1,minute%10,color) ;
  fillw (x1-sqx-5,y1+sqy,color|ZHUZHKA,1) ;
  fillw (x1-sqx-5,y1+sqy+2,color|ZHUZHKA,1) ;
  if (!Cae) {
    fillw (maxx-3,maxy-1,color|'C',1) ;
    fillw (maxx-2,maxy-1,color|'A',1) ;
    fillw (maxx-1,maxy-1,color|'E',1) ;
  }
}

void __cdecl binkc_load (struct scp * sc) {
  program_name[0] = '\r' ;
  set_new_random () ;
  scr_blanked = 0 ;
  maxx = sc->xmax ;
  maxy = sc->ymax ;
  sqx = maxx/10-2 ;
  sqy = maxy/6-2 ;
  setup_colors () ;
}

void __cdecl binkc_one_step (void) {
  if (scr_blanked==0) {
    scr_blanked = 1 ;
    hour = 25 ;
    minute = 61 ;
  }
  if (new_minute ()==1)
    print_time () ;
}

void __cdecl binkc_unload () {
  scr_blanked = 0 ;
}

#ifdef TEST

static int kbhit (void) {
  KBDKEYINFO k ;
  USHORT ret = KbdPeek (&k,0) ;
  return ret ? 0 : k.fbStatus & KBDTRF_FINAL_CHAR_IN ;
}

void main (void) {
  struct scp sc1 ;
  sc1.xmax = 80 ;
  sc1.ymax = 25 ;
  binkc_load (&sc1) ;
  while (!kbhit ()) {
    binkc_one_step () ;
    DosSleep (1) ;
  }
  binkc_unload () ;
  exit (0) ;
}

#endif