#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include "../winuser.h"
#include "../../kernel/scolobj.h"

/* reflexes type TIMER */
#define RFLTIMER_NB     1
#define RFLTIMER_CLOCK  0

int OBJTYPTIMER;


int OBJTYPTIMERMM;

#define MT_NB 4096
int mt_per[MT_NB];
int mt_nxt[MT_NB];
int mt_param[MT_NB];
int (*mt_fun[MT_NB])(int i,int param);
int mt_ind=0;

int mt_nxtvirt;

int GetTickCount()
{
  struct timeval tm;
  int t;

  gettimeofday(&tm,NULL);
  t=(tm.tv_sec*1000)+(tm.tv_usec/1000);
  return t;
}

int mt_new()
{
	int i;
	for(i=0;i<mt_ind;i++) if (!mt_per[i]) return i;
	if (mt_ind>=MT_NB) return -1;
	mt_ind++;
	return mt_ind-1;
}

int mt_event()
{
  int t,i;

//  MMechostr(1,"### event %d\n",sys);
  t=GetTickCount();
  if (t==mt_nxtvirt-1) t=mt_nxtvirt;

  for(i=0;i<mt_ind;i++) if (mt_per[i])
  {
	  if (t-mt_nxt[i]>=0)
	  {
		  (*mt_fun[i])(i,mt_param[i]);
		  if (mt_per[i]) while(t-mt_nxt[i]>=0) mt_nxt[i]+=mt_per[i];
	  }
  }
  return 1;
}


int mt_timeout()
{
	int tmin,first,d,i;

	first=1;
	for(i=0;i<mt_ind;i++) if (mt_per[i])
	{
		if (first)
		{
			tmin=mt_nxt[i];
			first=0;
		}
		else if (tmin-mt_nxt[i]>0) tmin=mt_nxt[i];
	}
	if (first) return -1;
	d=tmin-GetTickCount();
	if (d<=10) d=10;
	mt_nxtvirt=tmin;
	return d;
}

int mt_start(int per,int param,int (*fun)(int i,int param))
{
	int i;

	if ((per<=0)||(fun==NULL)) return -1;
	if (per<10) per=10;
	i=mt_new();
	if (i<0) return -1;
	mt_per[i]=per;
	mt_param[i]=param;
	mt_fun[i]=fun;
	mt_nxt[i]=GetTickCount()+per;
	return i;
}

int mt_del(int i)
{
//	MMechostr(1,"### del %d\n",i);
	if ((i<0)||(i>=MT_NB)) return -1;
	mt_per[i]=0;
	while((mt_ind>0)&&(mt_per[mt_ind-1]==0)) mt_ind--;
	return 0;
}

int ClockCB(int sys,int param)
{
	int k;
	mmachine m;

	m=(mmachine)param;
//    MMechostr(1,"### clockCB %d\n",sys);
	k=OBJbeginreflex(m,OBJTYPTIMERMM,sys,RFLTIMER_CLOCK);
	if (k==0) OBJcallreflex(m,0);
	return 0;
}

int TMMMstarttimer(mmachine m)
{
  int freq,k,sys;

  freq=MMget(m,0);
  if ((MMget(m,1)==NIL)||(freq<=0))
    {
      MMpull(m);
      MMset(m,0,NIL);
      return 0;
    }
  sys=mt_start(freq>>1,(int)m,ClockCB);
  if (sys<0)
    {
      MMpull(m);
      MMset(m,0,NIL);
      return 0;
    }
  if (MMpush(m,sys*2)) return MERRMEM;
  if (MMpush(m,0*2)) return MERRMEM;
  if (MMpush(m,3*2)) return MERRMEM;
  if (k=MBdeftab(m)) return k;
  return OBJcreate(m,OBJTYPTIMERMM,sys,-1,0);
}

int TMMMdeltimer2(mmachine m,int handsys,int objm)
{
  mt_del(handsys);
  return 0;
}

int TMMMdeltimer(mmachine m)
{
  int i;
  
  i=MMget(m,0)>>1;
  if (i==NIL) return 0;
  OBJdelTH(m,OBJTYPTIMERMM,MMfetch(m,i,1)>>1);
  MMset(m,0,0);
  return 0;
}

int TMMMrfltimer(mmachine m)
{
  return OBJaddreflex(m,OBJTYPTIMERMM,RFLTIMER_CLOCK);
}




int _keybdstate(mmachine m)
{ m->pp+=0;return MMpush(m,NIL); }
int _GETscreenPos(mmachine m)
{ m->pp+=0;return MMpush(m,NIL); }
int _funlist(mmachine m)
{ m->pp+=1;return MMpush(m,NIL); }
int _CtoScol(mmachine m)
{ m->pp+=1;return MMpush(m,NIL); }
int MMjoystick(mmachine m)
{ m->pp+=1;return MMpush(m,NIL); }
#define NTXTPKG 9
char* txtname[NTXTPKG]=
{"Timer","_starttimer","_rfltimer","_deltimer",
 "_keybdstate","_GETscreenPos","_funlist","_CtoScol",
 "_joystick"
};
int (*txtfun[NTXTPKG])(mmachine m)=
{
 NULL,TMMMstarttimer,TMMMrfltimer,TMMMdeltimer,
 _keybdstate,_GETscreenPos,_funlist,_CtoScol,
 MMjoystick
};
int txtnarg[NTXTPKG]=
{TYPTYPE,2,3,1,
 0,0,1,1,
 1
};


char* txttype[NTXTPKG]=
{NULL,"fun [Chn I] Timer","fun [Timer fun [Timer u0] u1 u0] Timer","fun [Timer] I",
 "fun [] I","fun [] [I I]","fun [Env] [Sold I I Sold r1]","fun [Sold] S",
 "fun [I] [I I I I]"
};

int SCOLloadtxtsys(mmachine m)
{
  OBJTYPTIMERMM=OBJregister(RFLTIMER_NB,0,TMMMdeltimer2,"OBJTYPTIMERMM");
  return PKhardpak(m,"txtsys.pkg",NTXTPKG,txtname,txtfun
		   ,txtnarg,txttype);
}
