/* $Id: swverid.c,v 1.12 2000/03/28 00:39:49 jhl Exp jhl $
 *  swverid.c: POSIX-7.2 Object Identification Routines.
 */

/*
   Copyright (C) 1998,2004  James H. Lowe, Jr.  <jhlowe@acm.org>
   All rights reserved.
  
   COPYING TERMS AND CONDITIONS
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.
  
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
  
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
 */

#include "swuser_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <limits.h>
#include "strob.h"
#include "swverid.h"
#include "swlib.h"
#include "swutilname.h"

static 
struct VER_ID *
parse_version_id(char * verid)
{
	struct VER_ID *ver_id=(struct VER_ID*)malloc(sizeof(struct VER_ID));
	char *s = verid;
	char *olds;

	olds = s;
	while (isalpha(*s)) s++;
	if ((olds - s) == 0 || (s - olds) > 2) {
		swbis_free(ver_id);
		return NULL;
	}
	strncpy(ver_id->ver_idM, olds, (int)(s - olds));
	ver_id->ver_idM[(int)(s - olds)] = '\0';

	olds = s;
	while (	*s == '=' ||
		*s == '<' ||
		*s == '>'
	) s++;

	if ((olds - s) == 0 || (s - olds) > 2) {
		swbis_free(ver_id);
		return NULL;
	}
	strncpy(ver_id->rel_opM, olds, (int)(s - olds));
	ver_id->rel_opM[(int)(s - olds)] = '\0';

	olds = s;
	strncpy(ver_id->valueM, olds, sizeof(ver_id->valueM));
	ver_id->valueM[sizeof(ver_id->valueM) - 1] = '\0';
	
	return ver_id;
}

static 
int
parse_version_id_string(SWVERID * swverid, char * verid_string)
{
	struct VER_ID *verid;
	STROB * buf = strob_open(10);
	char  *s;

	s = strob_strtok(buf, verid_string, ",");
	while (s) {
		verid = parse_version_id(s);	
		if (verid == (struct VER_ID *)(NULL)) return -1;
		swverid_add_verid(swverid, verid);
		s = strob_strtok(buf, NULL, ",");
	}
	strob_close(buf);
	return 0;
}

static
int
parse_swspec_string (SWVERID * swverid)
{
	char * source = swverid->source_copyM;
	char * tag;
	char * tags;
	char * verids;
	char * verid;
	int ret;
	STROB * tmp = strob_open(20);
	STROB * tag_tmp2 = strob_open(20);
	STROB * ver_tmp2 = strob_open(20);

	if (!source || strlen(source)  == 0) return -2;
	cplob_shallow_reset(swverid->taglistM);
	tags = strob_strtok(tmp, source, ",");
	tag = strob_strtok(tag_tmp2, tags, ".");
	while (tag) {
		cplob_add_nta(swverid->taglistM, strdup(tag));
		tag = strob_strtok(tag_tmp2, NULL, ".");
	}

	verids = strob_strtok(tmp, NULL, ",");
	if (verids) {
		verid = verids;
		while (verid) {
			ret = parse_version_id_string(swverid, verid);
			if (ret) {
				fprintf(stderr, "%s: error parsing version id [%s]\n",
					swlib_utilname_get(),  verid);
				return -1;
			}
			verid = strob_strtok(tmp, NULL, ",");
		}
	}
	strob_close(tmp);
	strob_close(tag_tmp2);
	strob_close(ver_tmp2);
	return 0;
}

static 
int
classify_namespace (char * object_kw)
{
	if (!object_kw)  return SWVERID_NS_NA;
	if (!strncmp("fileset", object_kw, 7)) {
		return SWVERID_NS_MID;
	} else if (!strncmp("controlfile", object_kw, 11)) {
		return SWVERID_NS_MID;
	} else if (!strncmp("subproduct", object_kw, 10)) {
		return SWVERID_NS_MID;
	} else if (!strncmp("product", object_kw, 7)) {
		return SWVERID_NS_TOP;
	} else if (!strncmp("bundle", object_kw, 6)) {
		return SWVERID_NS_TOP;
	} else if (!strncmp("file", object_kw, 4)) {
		return SWVERID_NS_LOW;
	} else {
		return SWVERID_NS_NA;
	}
}

/* ------------------- Public Functions ---------------------------------*/

SWVERID *
swverid_open(char * object_keyword, char *swversion_string)
{
	SWVERID *swverid=(SWVERID*)malloc(sizeof(SWVERID));
	if (!swverid) return NULL;
	
	swverid->object_nameM=swlib_strdup("");
	swverid->taglistM = cplob_open(3);
	cplob_add_nta(swverid->taglistM, (char*)(NULL));
	swverid->catalogM=swlib_strdup("");
	swverid->comparison_codeM=SWVERID_CMP_EQ;
	swverid_set_namespace(swverid, object_keyword);
	swverid_set_object_name(swverid, object_keyword);
	swverid->ver_id_listM=(struct VER_ID*)(NULL);
	swverid->source_copyM = (char*)(NULL);
	swverid->use_path_compareM = 0;

	if (swversion_string != (char*)(NULL)) {
		swverid->source_copyM = swlib_strdup(swversion_string);
		parse_swspec_string(swverid);
	}	
	return swverid;
}

void
swverid_set_namespace(SWVERID * swverid, char * object_keyword)
{
	swverid->namespaceM = classify_namespace(object_keyword);
}

void
swverid_close(SWVERID * swverid)
{
	struct VER_ID *vid, *ver_id=swverid->ver_id_listM;
	while(ver_id){
		vid=ver_id->nextM;
		swbis_free(ver_id);
		ver_id=vid;			
	}
	if (swverid->object_nameM) {
		swbis_free(swverid->object_nameM);
		swverid->object_nameM = NULL;
	}
	if (swverid->source_copyM) {
		swbis_free(swverid->source_copyM);
		swverid->source_copyM = NULL;
	}
	/* FIXME this causes a core dump: cplob_close(swverid->taglistM); */
	swbis_free(swverid);
}

o__inline__
void
swverid_set_object_name(SWVERID * swverid, char *name)
{
	if (swverid->object_nameM) swbis_free(swverid->object_nameM);
	if (name)
		swverid->object_nameM=swlib_strdup(name);
	else
		swverid->object_nameM=swlib_strdup("");
}

o__inline__
char *
swverid_get_object_name(SWVERID * swverid)
{
	return swverid->object_nameM;
}

int
swverid_compare(SWVERID * swverid1_target, SWVERID * swverid2_candidate)
{
	char * tag1;	

	if (
		strcmp(swverid1_target->object_nameM,
			swverid2_candidate->object_nameM)
	) {
		return SWVERID_CMP_NEQ;
	}

	if (
		swverid1_target->namespaceM != SWVERID_NS_NA &&
		swverid1_target->namespaceM != swverid2_candidate->namespaceM
	) {
		return SWVERID_CMP_NEQ;
	}

	tag1 = cplob_val(swverid1_target->taglistM, 0);
	if (!tag1 || strlen(tag1) == 0) {
		 return SWVERID_CMP_EQ;
	}

	if (swverid1_target->use_path_compareM || swverid2_candidate->use_path_compareM) {
		if (!swlib_compare_8859(cplob_val(swverid1_target->taglistM,0),
				cplob_val(swverid2_candidate->taglistM,0))
		) {
			return SWVERID_CMP_EQ;
		} else {
			return SWVERID_CMP_NEQ;
		}
	} else { 	
		if (!strcmp(cplob_val(swverid1_target->taglistM,0), cplob_val(swverid2_candidate->taglistM,0))) {
			return SWVERID_CMP_EQ;
		} else {
			return SWVERID_CMP_NEQ;
		}
	}
}

int
swverid_add_attribute(SWVERID * swverid, char * object_keyword, char * keyword, char * value) {
	char ver_id[3];
	struct VER_ID *version_id;
	STROB * verid_string;
	int c = swverid_get_ver_id_char(object_keyword, keyword);

	if (strcmp(object_keyword, "file") == 0 || strcmp(object_keyword, "control_file") == 0) {
		swverid->use_path_compareM = 1;
	}
	
	ver_id[0] = ver_id[1] = ver_id[2] = '\0';
	if (c < 0) return 0;
	if (c == 0) {
		if (swverid->source_copyM) {
			swbis_free(swverid->source_copyM);
			swverid->source_copyM = NULL;
		}
		swverid->source_copyM = swlib_strdup(value);
		cplob_additem(swverid->taglistM, 0, swverid->source_copyM);
		return 1;
	}

	if (object_keyword) ver_id[0] = *object_keyword;
	ver_id[1] = (char)(c);

	verid_string = strob_open(24);
	strob_strcpy(verid_string, ver_id);
	strob_strcat(verid_string,"=");
	strob_strcat(verid_string, value);

	version_id = parse_version_id(strob_str(verid_string));
	strob_close(verid_string);
	if (!version_id) {
		return -1;
	}
	swverid_add_verid(swverid, version_id);
	return 1;
}

int
swverid_get_comparison_sense(SWVERID * swverid1, SWVERID * swverid2)
{
	return 0;
}

Swverid_Cmp_Code
swverid_get_comparison_code(SWVERID * swverid)
{
	return swverid->comparison_codeM;
}

void
swverid_set_comparison_code(SWVERID * swverid, Swverid_Cmp_Code code)
{
	swverid->comparison_codeM=code;
}

char *
swverid_get_tag(SWVERID * swverid, int n)
{
	return cplob_val(swverid->taglistM, n);
}

void
swverid_set_tag(SWVERID * swverid, char * key, char *value)
{
	if (!strcmp(key, "catalog")) {
		if (swverid->catalogM) { 
			swbis_free(swverid->catalogM);
			swverid->catalogM = NULL;
		}
		swverid->catalogM=swlib_strdup(value);
	} else {
		if (cplob_val(swverid->taglistM,0)) { 
			swbis_free(cplob_val(swverid->taglistM,0));
		}
		cplob_additem(swverid->taglistM, 0, swlib_strdup(value));
	}
}

int 
swverid_get_ver_id_char(char * object, char * attr_name)
{
	if (!strcmp(attr_name, SW_A_revision)) {
		return SWVERID_VERID_REVISION;
	}
	else if (!strcmp(attr_name, SW_A_architecture)) {
		return SWVERID_VERID_ARCHITECTURE;
	}
	else if (!strcmp(attr_name, SW_A_vendor_tag)) {
		return SWVERID_VERID_VENDOR_TAG;
	}
	else if (!strcmp(attr_name, SW_A_location)) {
		return SWVERID_VERID_LOCATION;
	}
	else if (!strcmp(attr_name, SW_A_qualifier)) {
		return SWVERID_VERID_QUALIFIER;
	}
	else if (!strcmp(attr_name, SW_A_tag)) {
		return 0;
	}
	else if (!strcmp(attr_name, SW_A_path)) {
		if (!strcmp(object, "file") || !strcmp(object, SW_A_distribution))
			return 0;
		else 
			return -1;
	}
	else {
		return -1;
	}
}

int
swverid_compare_ver_id(SWVERID * swverid1, SWVERID * swverid2)
{
	return 0;
}

void
swverid_add_verid(SWVERID * swverid, struct VER_ID  * verid) {
	struct  VER_ID  *prev;
	struct  VER_ID  *last = swverid->ver_id_listM;
	verid->nextM = NULL;

	if (!last) {
		swverid->ver_id_listM = verid;
		return;
	}	

	while (last) {
		prev = last;
		last = last->nextM;
	}
	prev->nextM = verid;
}

char *
swverid_print(SWVERID * swverid, char * buf, int buflen)
{
	char * s;
	int i = 0;
	char * ret = (char *)(NULL);
	STROB * version = strob_open(32);
	struct  VER_ID  *next = swverid->ver_id_listM;

	strob_strcpy(version, "");
	while ((s = cplob_val(swverid->taglistM, i++))) {
		if (i > 1) strob_strcat(version, ".");
		strob_strcat(version, s);
	}

	while (next) {
		strob_strcat(version, ",");
		strob_strcat(version, next->ver_idM);
		strob_strcat(version, next->rel_opM);
		strob_strcat(version, next->valueM);
		next = next->nextM; 
	}

	if ((int)strlen(strob_str(version)) <= buflen - 1) {
		strcpy(buf, strob_str(version));
		ret = buf;
	}
	return ret;
}

CPLOB *
swverid_u_parse_swspec(SWVERID * swverid, char * swspec)
{
	CPLOB * list;
	CPLOB * savecplob;
	char * savesource;

	savecplob = swverid->taglistM;
	list = cplob_open(3);
	swverid->taglistM = list;
	savesource = swverid->source_copyM;
	swverid->source_copyM = strdup(swspec);
		
	parse_swspec_string(swverid);

	free(swverid->source_copyM);		
	swverid->taglistM = savecplob;
	swverid->source_copyM = savesource;
	return list;
}

