#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/classes.h>
#include <intuition/classusr.h>
#include <intuition/cghooks.h>
#include <intuition/icclass.h>
#include <utility/tagitem.h>
#include <utility/hooks.h>
#include <clib/utility_protos.h>
#include <graphics/graphint.h>
#include <clib/alib_protos.h>
#include <clib/intuition_protos.h>
#include "rkmmodel.h"

#define DEFAULTLIMIT 100

struct RKMModData {
  ULONG currval;
  ULONG limit;
  int id;
};

ULONG dispatchRKMModel(Class *,Object *,Msg);
void NotifyCurrVal(Class *,Object *,struct opUpdate *,\
		   struct RKMModData *);
Class *initRKMModClass(void)
{
  Class *cl=NULL;
  extern ULONG HookEntry();
  
  if((cl=MakeClass(NULL,"modelclass",NULL,sizeof(struct RKMModData),\
		   0))!=NULL)
    {
      cl->cl_Dispatcher.h_Entry=HookEntry;
      cl->cl_Dispatcher.h_SubEntry=dispatchRKMModel;
    }
  return cl;
}

BOOL freeRKMModClass(Class *cl)
{
  return FreeClass(cl);
}

ULONG dispatchRKMModel(Class *cl,Object *o,Msg msg)
{
  struct RKMModData *mmd;
  APTR retval=NULL;
  switch(msg->MethodID)
    {
    case OM_NEW:
      if((retval=(APTR)DoSuperMethodA(cl,o,msg))!=NULL)
	{
	  mmd=INST_DATA(cl,retval);
	  mmd->currval=GetTagData(RKMMOD_CurrVal,0,\
				  ((struct opSet *)msg)->ops_AttrList);
	  mmd->limit=GetTagData(RKMMOD_Limit,0,\
				((struct opSet *)msg)->ops_AttrList);
	  mmd->id=GetTagData(RKMMOD_Id,0,((struct opSet *)msg)->ops_AttrList);
	}
      break;
    case OM_SET:
    case OM_UPDATE:
      mmd=INST_DATA(cl,o);
      DoSuperMethodA(cl,o,msg);
      {
	struct TagItem *tstate,*ti;
	
	ti=((struct opSet *)msg)->ops_AttrList;
	tstate=ti;
	while(ti=NextTagItem(&tstate))
	  {
	    switch(ti->ti_Tag)
	      {
	      case RKMMOD_CurrVal:
		if((ti->ti_Data)>mmd->limit) mmd->currval=mmd->limit;
		  else
		    {
		      if((ti->ti_Data)<0) mmd->currval=0;
		      else mmd->currval=ti->ti_Data;
		    }
		NotifyCurrVal(cl,o,(struct opUpdate *)msg,mmd);
		retval=(APTR)1;
		break;
	      case RKMMOD_Up:
		mmd->currval++;
		if((mmd->currval)>mmd->limit) mmd->currval=mmd->limit;
		NotifyCurrVal(cl,o,(struct opUpdate *)msg,mmd);
		retval=(APTR)1;
		break;
	      case RKMMOD_Down:
		mmd->currval--;
		if((mmd->currval) == -1) mmd->currval=0;
		NotifyCurrVal(cl,o,(struct opUpdate *)msg,mmd);
		retval=(APTR)1;
		break;
	      case RKMMOD_Limit:
		mmd->limit=ti->ti_Data;
		break;
	      case RKMMOD_Id:
		mmd->id=ti->ti_Data;
		break;
	      }
	  }
      }
      break;
    case OM_GET:
      mmd=INST_DATA(cl,o);
      switch(((struct opGet *)msg)->opg_AttrID)
	     {
	     case RKMMOD_CurrVal:
	       *(((struct opGet *)msg)->opg_Storage)=mmd->currval;
	       retval=(Object *)TRUE;
	       break;
	     case RKMMOD_Id:
	       *(((struct opGet *)msg)->opg_Storage)=mmd->id;
	       retval=(Object *)TRUE;
	       break;
	     default:
	       retval=(APTR)DoSuperMethodA(cl,o,msg);
	       break;
	     }
      break;
    default:
      retval=(APTR)DoSuperMethodA(cl,o,msg);
      break;
    }
  return (ULONG)retval;
}

void NotifyCurrVal(Class *cl,Object *o,struct opUpdate *msg,\
		   struct RKMModData *mmd)
{
  struct TagItem tt[3];
  
  tt[0].ti_Tag=RKMMOD_CurrVal;
  tt[0].ti_Data=mmd->currval;
  tt[1].ti_Tag=RKMMOD_Id;
  tt[1].ti_Data=mmd->id;
  tt[2].ti_Tag=TAG_DONE;

  DoSuperMethod(cl,o,OM_NOTIFY,tt,msg->opu_GInfo,\
		((msg->MethodID == OM_UPDATE) ?	(msg->opu_Flags) : 0));
}

