#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "dioctl.h"
#include "dioname.h"

Map *DIOMapNamePin;
uint8 TotalDioCount;
uint8 DioCapabilities[256];

static inline void DIOCapsCanDriveLow(uint8 *caps,int set) {
	if (!set) {
		*caps &= ~4;
	} else {
		*caps |= 4;
	}
}

static inline void DIOCapsCanDriveHigh(uint8 *caps,int set) {
	if (!set) {
		*caps &= ~2;
	} else {
		*caps |= 2;
	}
}

static inline void DIOCapsCanTristate(uint8 *caps,int set) {
	if (!set) {
		*caps &= ~1;
	} else {
		*caps |= 1;
	}
}

extern int MapCompareKey(Map a,Map b);
int MapComparePartial(Map a,Map b) {
  int len = strlen(b.key);
  int strmatch = strncmp(a.key,b.key,len);
  if (!strmatch) {
    return a.val - b.val;
  } else {
    return strmatch;
  }
}

// From a config file, we must parse each line into "name=value".
// we then call DIONameAssignment.  From the net API, we get
// these values already and call the same function, but with init=0
// Some names are not settable except when init=1
// performs any required side effects of the assignment
// returns 1 if the assignment succeeded, else returns 0
int DIONameAssignment(Map **map,char *str,int value,int init) {
        int i,connectorNum,connectorPin,pin;
	char *buf,*str1;
	Map *found,val,fnd;
	// automatic connector to connector name assignment
	if (2==sscanf(str,"attrib.Connector.%d.%d",
		&connectorNum,&connectorPin)) {
		if (!init) {
			return 0; // read-only after init
		}
		val.key = "attrib.Connector.Name.";
		val.val = connectorNum;
		found=MapFindBinary(*map,val,MapComparePartial);
		if (!found) { // found->key == 0 && found->val == 0) {
			// no connector name defined for this connector
			// so we can't define a pin name for it!
			// or we could just default to "CN" or something
			// but that might conflict or be unexpected
			return 0;
		}
		val.key = found->key;
		// val.key+22 advances past "attrib.Connector.Name."
		buf = malloc(strlen(val.key+22)+32); // a bit extra allocated
		sprintf(buf,"%s%d",val.key+22,connectorPin);
		// now create the new entry
		val.key = strdup(buf);
		val.val = value;
		// now re-using val to hold replaced entry, if any
		//i=MapInsertSorted(map,val,MapCompareKey);
		MapReplaceSorted(map,val,MapCompareKey);
		// TO DO: why does replacing Insert with Replace cause a segfault?
		// if there was a replaced entry, free the key
                // note: can't do the below if inserting!
                //if (val.key) free(val.key);
		goto DIONameAssignmentDo;
	}
	// special pin attribute assignments
	if (!strncmp(str,"attrib.",7) && isdigit(str[7])) {
		pin=0;
		str1 = str + 7;
		while (isdigit(*str1)) {
			pin = pin * 10 + (*str1-'0');
			str1++;
		}
		if (*str1 != '.') return 0;
		str1++;
		if (!strncmp(str1,"canInput",8)) {
			if (!init) return 0;
			DIOCapsCanTristate(DioCapabilities+pin,1);
			goto DIONameAssignmentDo;
		}
		if (!strncmp(str1,"canDriveHigh",12)) {
			if (!init) return 0;
			DIOCapsCanDriveHigh(DioCapabilities+pin,1);
			goto DIONameAssignmentDo;
		}
		if (!strncmp(str1,"canDriveLow",11)) {
			if (!init) return 0;
			DIOCapsCanDriveLow(DioCapabilities+pin,1);
			goto DIONameAssignmentDo;
		}
		if (!strncmp(str1,"inputOnly",9)) {
			if (!init) return 0;
			DIOCapsCanDriveLow(DioCapabilities+pin,0);
			DIOCapsCanDriveHigh(DioCapabilities+pin,0);
			DIOCapsCanTristate(DioCapabilities+pin,1);
			goto DIONameAssignmentDo;
		}
		if (!strncmp(str1,"outputOnly",10)) {
			if (!init) return 0;
			DIOCapsCanDriveLow(DioCapabilities+pin,1);
			DIOCapsCanDriveHigh(DioCapabilities+pin,1);
			DIOCapsCanTristate(DioCapabilities+pin,0);
			goto DIONameAssignmentDo;
		}
		if (!strncmp(str1,"normalIO",8)) {
			if (!init) return 0;
			DIOCapsCanDriveLow(DioCapabilities+pin,1);
			DIOCapsCanDriveHigh(DioCapabilities+pin,1);
			DIOCapsCanTristate(DioCapabilities+pin,1);
			goto DIONameAssignmentDo;
		}
		// non-special attribute, fall through
	}
 DIONameAssignmentDo:
	val.key = strdup(str);
	val.val = value;
	MapReplaceSorted(map,val,MapCompareKey);
}

// parse str according to "name=value"
// then call DIONameAssignment to process
// returns 1 on success, or 0 on failure
int DIOConfigLineProcess(Map **map,char *str) {
	char *str0 = str;
	
	while (*str && *str != '=') str++;
	if (*str != '=') return 0;
	*str = 0;
	str++;
	return DIONameAssignment(map,str0,atoi(str),1);
	return 1;
}

// max name length is 256, so we only allow 300 bytes per line
int DIOConfigFileProcess(Map **map,char *filename) {
	char buf[300];
	int i;
	
	FILE *f = fopen(filename,"r");
	if (!f) {
		perror(filename);
		return 0;
	}
	while (!feof(f)) {
		fgets(buf,300,f);
		if (buf[0] == 0) goto DIOConfigFileProcessEnd;
		DIOConfigLineProcess(map,buf);
	}
	DIOConfigFileProcessEnd:
	fclose(f);
	for (i=0;i<256;i++) {
		if (DioCapabilities[i] != 0 && i+1 > TotalDioCount) {
			TotalDioCount = i+1;
		}
	} 
	fprintf(stderr,"DIOConfigFileProcess(%s) ended, TotalDioCount=%d\n",filename,TotalDioCount);
	return 1;
}

#if 0
/*
this is trickier than it looks, due to the fact that we don't store everything ripe for the picking.  here is what we need to do:
1. create an int pointer that we set to the connector to DIO mapping table
2. create a table allocated with the number of DIOs from the arch, set from ???
   well let's just make it have 256 elements
     [dio number] dio name, connector name
3. create the table. must do first since it won't be constructed in order
	
4. now print out the table in order
*/
void DumpDioInfo() {
	struct table {
		int conn;
		char *name;
	} tab[256];
	int i;
	
	// dio, names, num_names	
	for (i=0;i<256;i++) {
		tab[i].conn = -1;
	}
	
	for (i=0;i<200;i++) {
		if (arch_dio[i] != -1) {
			tab[arch_dio[i]].conn = i;
			tab[arch_dio[i]].name = getDioNameFromNumber(arch_dio[i]);
		}
	}
	for (i=0;i<256;i++) {
		if (tab[i].conn != -1) {
			printf("%d,%s,CN%d-%d\n",i,tab[i].name,
				1+(tab[i].conn/100),1+(tab[i].conn%100));
		}
	}
}

#endif

/*
  Author: Michael Schmidt (michael@embeddedARM.com)
 */
