#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "tcplib.h"
#include "lib.h"
#include "dotlock.h"
#include "lprintf.h"


#ifndef FALSE
#define FALSE 0
#endif

#ifndef TRUE
#define TRUE (!FALSE)
#endif

#include "defines.h"

static int silent=TRUE;
int dotlock_already(char *ufile,char *lfile, int logit);

int dotlock_lock(char *lfile, int waitsec, int too_old_secs, char *reason)
{
	char ufile[BFSZ];
	char host[BFSZ];
	int nbad = 0;
	int start;
	int once = TRUE;
	struct stat st;
	FILE *f;

	start = time(NULL);
	tcp_hostname(host);
	sprintf(ufile,"%s_%d_%s",lfile,getpid(),host);

	for (;(time(NULL)-start<waitsec) || once;) {
		once = FALSE;
		remove(ufile);
		if (stat(lfile,&st)==0) {  /* Seems to be a file there */
			if (st.st_mtime < (time(NULL)-too_old_secs)) {
//				if (!silent) printf("lock: File %s is %d seconds old, clearing it\n",lfile,time(NULL) - st.st_mtime);
				goto clear_lock;
			}
			if (st.st_nlink<2) {
				lib_msleep(100);
//				if (!silent) printf("lock: File %s has bad link count checking again %d %d/10\n",lfile,st.st_nlink,nbad);
				nbad++;
				if (nbad>=10) {
clear_lock:				remove(ufile);
					remove(lfile);
				}
			}
		}

		errno = 0;
		f = fopen(ufile,"w");
		if (f==NULL) {
//			if (!silent) printf("Could not create (%s) %s\n",ufile,strerror(errno));
			lprintf(reason,100,"create (%s) (%s)",strerror(errno),ufile);
			return FALSE;
		}
		fclose(f);

		if (link(ufile,lfile)==0) {
//			if (!silent) printf("lock: We got the lock, yay %s\n",lfile);
			if (!dotlock_already(ufile,lfile,!silent)) {
				remove(ufile);
				continue;
			}
			return TRUE;
		}
	}
	strcpy(reason,"Currently in use on another channel, close other clients and try later");
	return FALSE;
}
int dotlock_unlock(char *lfile, char *reason)
{
	char ufile[BFSZ];
	char host[BFSZ];
	int nbad = 0;

	tcp_hostname(host);
	sprintf(ufile,"%s_%d_%s",lfile,getpid(),host);
	if (remove(ufile)!=0) ;//if (!silent) printf("unlock: remove (%s) %s\n",ufile,strerror(errno));
	if (unlink(lfile)!=0) ; //if (!silent) printf("unlock: remove (%s) %s\n",lfile,strerror(errno));
	return TRUE;
}
int dotlock_already(char *ufile,char *lfile, int logit)
{
	struct stat st,st1;
	if (silent) logit = FALSE;
	if (stat(ufile,&st1)==-1) {
		return FALSE;
	}
	if (st1.st_nlink!=2) {
//		if (logit) printf("lock: Only %d links so we couldn't possibly have the lock\n",st1.st_nlink);
		return FALSE;
	}
	if (stat(lfile,&st)==-1) {
//		if (logit) printf("lock: stat failed on lockfile %s %s\n",lfile,strerror(errno));
		return FALSE;
	}
	if ((st.st_rdev == st1.st_rdev) &&  (st.st_ino  == st1.st_ino)) {
		return TRUE;
	}
//	if (logit) printf("lock: %d %d %s\n",(int)st1.st_rdev,(int)st1.st_ino,ufile);
//	if (logit) printf("lock: %d %d %s\n",(int)st.st_rdev,(int)st.st_ino,lfile);
//	if (logit) printf("lock: The lock is linked to the wrong FILE (%s) (%s)!!!!\n",ufile,lfile);
	return FALSE;
}
