static    char    sccsid[]="%Z% %M% %I% %E% %U%";
/********************************************************************/
/*	clsort.c														*/
/*							2009/04/01 Ver 1.00  by A.Kobayashi		*/
/********************************************************************/
#include "colmn.h"

extern CLCOMMON  CLcommon;
extern CLPRTBL   *pCLprocTable;
extern GlobalCt  *pGlobTable;
extern int giOptions[];

static int giOpt,giNPos,*giPos;

/****************************************/
/*										*/
/****************************************/
static int _comp_n(col,argv1,argv2,at1,at2)
int col;
char **argv1,*at1,**argv2,*at2;
{
	int d,ix,atr1,atr2;
	char *s1,*s2;
	double d1,d2;

	s1 = argv1[col];
	s2 = argv2[col];
	ix = col-2;
	atr1 = at1[ix];
	atr2 = at2[ix];
/*
printf("_comp_n: col=%d atr1=%d atr2=%d s1=%08x s2=%08x\n",col,atr1,atr2,s1,s2);
*/
	if (atr1==DEF_ZOK_FLOA || atr2==DEF_ZOK_FLOA) {
		if (atr1 == DEF_ZOK_FLOA) memcpy(&d1,s1,sizeof(double));
		else d1 = (int)s1;
		if (atr2 == DEF_ZOK_FLOA) memcpy(&d2,s2,sizeof(double));
		else d2 = (int)s2;
		if (d1 == d2) d = 0;
		else if (d1 > d2) d = 1;
		else d = -1;
/*
printf("_comp_n: d1=%f d2=%f d=%d\n",d1,d2,d);
*/
	}
	else d = (int)s1 - (int)s2;
	return d;
}

/****************************************/
/*										*/
/****************************************/
static int _sort_func_pos(a,b)
char ***a,***b;
{
	int i,len1,len2,pos,len,d,l1,l2,ord,col;
	char *s1,*s2;
	char **argv1,*at1,**argv2,*at2;

	argv1 = *a;
	argv2 = *b;
	at1 = argv1[1];
	at2 = argv2[1];
	s1 = argv1[2];
	s2 = argv2[2];
/*
printf("_sort_func_pos: giNPos=%d s1=%08x s2=%08x\n",giNPos,s1,s2);
*/
	if (giNPos) {
		len1 = len2 = 0;
		if (s1) len1 = strlen(s1);
		if (s2) len2 = strlen(s2);
		for (i=0;i<giNPos;i+=3) {
			if (!(pos = giPos[i])) continue;
			pos--;
			ord = giPos[i+2];
/*
printf("_sort_func_pos: i=%d ord=%08x pos=%d\n",i,ord,pos);
*/
			if (ord & 0x06) {
				col = giPos[i+1]+2;
				d = _comp_n(col,argv1,argv2,at1,at2);
			}
			else if (!s1 || !s2) {
				d = -1;
			}
			else {
				len = giPos[i+1];
				if (!len) {
					len = len1 - pos;
					if ((d=len2-pos) > len) len = d;
				}
				if (pos >= len1) {
					if (pos >= len2) return 0;
					d = -1;
				}
				else if (pos >= len2) d = 1;
				else {
					if ((d=len1-pos)<(l1=len)) l1 = d;
					if ((d=len2-pos)<(l2=len)) l2 = d;
					if ((len=l1) > l2) len = l2;
					if (!(d=akxmemcmp(s1+pos,s2+pos,len))) {
						if (l1 < l2) d = -1;
						else if (l1 > l2) d = 1;
					}
				}
			}
/*
printf("_sort_func_pos: d=%d\n",d);
*/
			if (d) {
				if (ord & 0x01) d = -d;
				return d;
			}
		}
		return 0;
	}
	else return akxstrcmp(s1,s2);
}

/****************************************/
/*										*/
/****************************************/
static int _sort_func_col(a,b)
char ***a,***b;
{
	int i,col,d,ord;
	char *at1,*at2,**argv1,**argv2;

	argv1 = *a;
	argv2 = *b;
	at1 = argv1[1];
	at2 = argv2[1];
	for (i=0;i<giNPos;i+=2) {
		col = giPos[i]+2;
		ord = giPos[i+1];
		if (ord & 0x06) d = _comp_n(col,argv1,argv2,at1,at2);
		else d = akxstrcmp(argv1[col],argv2[col]);
		if (d) {
			if (ord & 0x01) d = -d;
			return d;
		}
	}
	return 0;
}

/****************************************/
/*										*/
/****************************************/
static int _get_sort_opt(pInfoParm,ipOpt,psep,popt)
tdtInfoParm *pInfoParm;
int  *ipOpt;
char *psep;
int  *popt;
{
	int iRc,len,opt,i,k,ln,argc;
	char c,*p,*argv[3],parm[256],sep;

	sep = '\0';
	opt = 0;
	*psep = sep;
	*popt = opt;
	*ipOpt = 0;
	if ((c=pInfoParm->pi_attr)==DEF_ZOK_BINA || c==DEF_ZOK_FLOA) {
		return cl_get_parm_bin(pInfoParm,ipOpt,"sort.opt:");
	}
	else if (c == DEF_ZOK_CHAR) {
		len = pInfoParm->pi_dlen;
		if (len > 0) {
			p = pInfoParm->pi_data;
			if ((argc=akxtgetargv(p,argv,2,parm,sizeof(parm))) < 0)
				return argc;
			for (i=0;i<argc;i++) {
				p = argv[i];
				c = toupper(*p);
				ln = strlen(p);
				if (strchr("FR",c)) ;
				else if (strchr("IC",c)) {
					*ipOpt |= 0x01;
					if ((k=akxnskipto(p,ln,"=")) < ln-1) sep = *(p+k+1);
				}
				else if (c == 'O') {
					if ((k=akxnskipto(p,ln,"=")) < ln-1) {
						if ((iRc=akxcgcvn(p+k+1,ln,&opt)) < 0) {
							ERROROUT1("_get_sort_opt: Option error rc=%d",iRc);
							return iRc;
						}
					}
				}
				else if (c == 'K') {
					*ipOpt |= 0x02;
					if ((k=akxnskipto(p,ln,"=")) < ln-1) {
						if (toupper(*(p+k+1)) == 'O') *ipOpt |= 0x04;
					}
				}
				else {
					return cl_get_parm_bin(pInfoParm,ipOpt,"sort.opt:");
				}
			}
		}
	}
	else {
		ERROROUT2(FORMAT(531),"_get_sort_opt",c);	/* %s: このデータ型(%c)は指定できません。 */
		return -1;
	}
	if (*psep = sep) opt |= AKX_ARGV_USE_ATTR2_SEP;
	*popt = opt;
/*
printf("_get_sort_opt: sep=[%c],opt=%08x\n",sep,opt);
*/
	return 0;
}

/****************************************/
/*										*/
/****************************************/
static int _get_sort_order(pInfoParm,ipOpt,flg)
tdtInfoParm *pInfoParm;
int *ipOpt,flg;
{
	int iRc,len,argc,i,val,opt;
	char c,*p,*argv[10],parm[256];

	*ipOpt = opt = 0;
	if (flg || (c=pInfoParm->pi_attr)==DEF_ZOK_BINA || c==DEF_ZOK_FLOA) {
		return cl_get_parm_bin(pInfoParm,ipOpt,"sort.order:");
	}
	else if (c == DEF_ZOK_CHAR) {
		len = pInfoParm->pi_dlen;
		if (len > 0) {
			p = pInfoParm->pi_data;
/*
printf("_get_sort_order: order=[%s]\n",p);
*/
			if ((argc=akxtgetargv(p,argv,10,parm,sizeof(parm))) < 0)
				return argc;
			for (i=0;i<argc;i++) {
				p = argv[i];
				c = toupper(*p);
				if (strchr("ACS",c)) ;
				else if (c == 'D') opt |= 1;
				else if (c == 'N') opt |= 2;
				else if (c == 'I') opt |= 4;
				else {
					if (iRc=cl_get_parm_bin(pInfoParm,&val,"sort.order:"))
						return iRc;
					opt |= val;
				}
			}
/*
printf("_get_sort_order: opt=%d\n",opt);
*/
			*ipOpt = opt;
		}
	}
	else {
		ERROROUT2(FORMAT(531),"_get_sort_order",c);	/* %s: このデータ型(%c)は指定できません。 */
		return -1;
	}
	return 0;
}

/****************************************/
/*										*/
/****************************************/
static int _set_n(attr,Val,col,argv,at,opt)
int attr,Val[],col,opt;
char **argv,*at;
{
	char *p;
	double d;
	int v;

	if (attr == DEF_ZOK_FLOA) {
		memcpy(&d,Val,sizeof(double));
/*
printf("sort:_set_n: v=%f\n",d);
*/
		if (opt & 0x04) {
			attr = DEF_ZOK_BINA;
			v = d;
			p = (char *)v;
/*
printf("sort:_set_n: to v=%d\n",v);
*/
		}
		else {
			if (!(p=cl_tmp_const_malloc(sizeof(double)))) return -31;
			memcpy(p,Val,sizeof(double));
		}
	}
	else {
/*
printf("sort:_set_n: v=%d\n",Val[0]);
*/
		p = (char *)CL_GET_VAL_BIN(Val);
	}
	argv[col] = p;
	at[col-2] = attr;
/*
printf("sort:_set_n: attr=%d\n",attr);
*/
	return 0;
}

/****************************************/
/*										*/
/****************************************/
static int _conv_n(p1,posl,col,argv,attr,opt)
int posl,col,opt;
char *p1,**argv,*attr;
{
	int Val[2],iAttr[4];

	iAttr[0] = DEF_ZOK_BINA;
	Val[0] = Val[1] =0;
	if (cl_conv_const_double(p1,posl,Val,NULL,iAttr) < 0) {
		Val[0] = Val[1] = 0;
	}
	return _set_n(iAttr[0],Val,col,argv,attr,opt);
}

/****************************************/
/*										*/
/****************************************/
int cl_ex_sort(pWork,nparm,ppParm)
char *pWork;
int  nparm;
tdtInfoParm **ppParm;	/* (to_index,from_index,max,opt,pos,len,order,...) */
{
	static char *_fn_="cl_ex_sort";
	tdtInfoParm *pInfoParm,rInfoParm,*pInfoParmW;
	tdtInfoParm ***pTBL_to,***pTBL;
	int iRc,i,maxargs,len,ix,n,alen,argc,pos,maxcol,col,j,v,Pos[3],posl,klen;
	long nm;
	char w1[32],*p1,**argv,c,*p,***pargv,*parm,*at,sep[2],*cpKey;
	tdtArrayIndex tIndex_to,tIndex;
	int  *index,iAttr[3],Val[2],attr,opt,sep_opt,*pSize;
	BlockCB tcrLCB;

	/* ソート結果を返す変数テーブルを取得する */
	pInfoParm = ppParm[0];
	if (iRc=cl_check_use_mapped_array(pInfoParm)) return iRc;
	if (iRc=cl_get_array_index_tbl(pInfoParm,&tIndex_to,&pTBL_to,"sort.index1:"))
		return iRc;
	if (iRc=cl_check_use_hash_array(pInfoParm,&tIndex_to)) return iRc;

	/* ソートする変数テーブルを取得する */
	pTBL =  NULL;
	pInfoParm = ppParm[1];
	if ((c=pInfoParm->pi_id)==' ' || c=='A') {
		if (iRc=cl_get_array_index_tbl(pInfoParm,&tIndex,&pTBL,"sort.index2:"))
			return iRc;
		index = tIndex.index;
		ix = index[3];
		nm = index[2];
		if (nm <= 0) nm = index[1];
	}
	else {
		if (iRc = cl_func_count(&nm,1,&pInfoParm,1)) return iRc;
		ix = 0;
		if ((c=pInfoParm->pi_id)==D_DATA_ID_LIST || c==D_DATA_ID_NARABI)
			akxs_rb_read(pInfoParm->pi_data,0);
	}
	maxargs = nm;

	/* ソートする個数を取得する */
	if (nparm>=3 && ppParm[2]->pi_dlen>0) {
		if (iRc=cl_get_parm_bin(ppParm[2],&maxargs,"sort.maxargs:")) return iRc;
/*
printf("sort: ix=%d nm=%d maxargs=%d\n",ix,nm,maxargs);
*/
		if (maxargs > nm) {
			/* %s: max_args(%d)が配列の個数(%d)を超えています。調整しました。 */
			ERROROUT3(FORMAT(532),_fn_,maxargs,n);
			maxargs = nm;
		}
	}

	/* ソート・オプションを取得する */
	if (nparm>=4 && ppParm[3]->pi_dlen>0) {
		if (iRc = _get_sort_opt(ppParm[3],&giOpt,sep,&sep_opt)) return iRc;
	}
	else {
		giOpt = 0;
		sep_opt = 0;
		sep[0] = '\0';
	}

	/* ソートする位置情報を取得する */
	maxcol = 0;
	if (nparm>=5) {
		giNPos = nparm - 4;
		if (!(giPos=(int *)cl_tmp_const_malloc((giNPos+2)*sizeof(int)))) return -1002;
		for (i=0;i<giNPos;i++) {
			pInfoParm = ppParm[i+4];
			if (giOpt & 0x01) {		/* Column or Item */
				j = i % 2;
				if (iRc = _get_sort_order(pInfoParm,&pos,!j)) return iRc;
				if (!j) {
					if (pos <= 0) {
							/* %s: 項目番号指定(%d)が不正です。 */
						ERROROUT2(FORMAT(533),_fn_,pos);
						return -1003;
					}
					if (pos > maxcol) maxcol = pos;
				}
			}
			else {					/* Fixed or Ranged or Key */
				j = i % 3;
				if (iRc = _get_sort_order(pInfoParm,&pos,j!=2)) return iRc;
				if (j == 0) {
					if (pos <= 0) {
						/* %s: 位置指定(%d)が不正です。 */
						ERROROUT2(FORMAT(534),_fn_,pos);
						return -1003;
					}
				}
				else if (j == 1) {
					if (pos < 0) {
						/* %s: 長さ指定(%d)が不正です。 */
						ERROROUT2(FORMAT(535),_fn_,pos);
						return -1004;
					}
				}
				else {
					if (pos & 0x06) maxcol++;
				}
			}
			giPos[i] = pos;
		}
		giPos[i++] = 0;
		giPos[i] = 0;
		if (giOpt & 0x01) {
			if (maxcol > 128) maxcol = 128;
		}
		else {
			if (giPos[0]==1 && giPos[1]==0 && giPos[2]==0) giNPos = 0;
		}
	}
	else {
		if (giOpt & 0x01) {
			giNPos = 2;
			giPos = Pos;
			giPos[0] = 1;
			giPos[1] = 0;
			maxcol = 1;
		}
		else giNPos = 0;
	}
/*
printf("sort: giOpt=%d giNPos=%d maxcol=%d\n",giOpt,giNPos,maxcol);
*/
	/* ソートするデータを配列に設定する */
	if (maxargs > 0) {
		if (!(pargv=(char ***)cl_tmp_const_malloc(maxargs*sizeof(char *)))) return -1005;
	}
	else pargv = NULL;
	n = 0;
	tcrLCB.iLoopCounter = ix;
	tcrLCB.iLoopMax = nm + ix;
	tcrLCB.pEachParm = ppParm[1];
	for (i=0;;i++,ix++) {
		if (n >= maxargs) break;
		klen = 0;
		cpKey = NULL;
		if (pTBL) {
			pInfoParm = cl_get_var_ent(pTBL,ix);
		}
		else {
			iRc = cl_loop_set_each(&tcrLCB,&pInfoParm,&cpKey);
			if (iRc) {
				if (iRc == 100) break;
				goto err;
			}
			if (giOpt & 0x02) {
				if (!cpKey) {
					ERROROUT1(FORMAT(536),_fn_);	/* %s: キー値が取得できません。 */
					return -1010;
				}
				klen = strlen(cpKey);
				if (giOpt & 0x04) {
					cl_set_parm_char(&rInfoParm,cpKey,klen);
					pInfoParm = &rInfoParm;
					klen = 0;
				}
			}
			tcrLCB.iLoopCounter++;
		}
		if (pInfoParm) {
			pInfoParmW = (tdtInfoParm *)cl_tmp_const_malloc(sizeof(tdtInfoParm));
			cl_gx_copy_info(pInfoParmW, pInfoParm);
			if (!(argv=(char **)cl_tmp_const_malloc((maxcol+3)*sizeof(char *)))) {
				iRc = -1006;
				goto err;
			}
			if (maxcol > 0) {
				if (!(at=cl_tmp_const_malloc(maxcol))) {
					iRc = -1007;
					goto err;
				}
			}
			else at = NULL;
			argv[0] = (char *)pInfoParmW;
			argv[1] = at;
			argv[2] = NULL;
			pargv[i] = argv;
			if ((attr=pInfoParmW->pi_attr)==DEF_ZOK_FLOA || attr==DEF_ZOK_BINA) {
				if ((giOpt & 0x01) && giNPos==2) opt = giPos[1];
				else if (!(giOpt & 0x01) && giNPos==3) opt = giPos[2];
				else opt = 0;
				if ((giOpt & 0x01) && giPos[0]==1 && (opt & 0x06)) {
					if (iRc=cl_get_parm_double(pInfoParmW,Val,NULL,iAttr)) goto err;
					if (iRc=_set_n(iAttr[0],Val,3,argv,at,opt)) goto err;
					n++;
					continue;
				}
			}
			p1 = w1;
			if ((iRc=len=parm_to_char(pInfoParmW,&p1,NULL)) < 0) goto err;
/*
printf("sort: i=%d p1=[%s]\n",i,p1,len);
*/
			iRc = -1021;
			alen = len + klen + 2;
			if (giOpt & 0x01) alen += len + 1 + maxcol;
			if (!(p = cl_tmp_const_malloc(alen))) goto err;
			if ((giOpt & 0x06) == 0x02) {
				memcpy(p,cpKey,klen);
				if (!(c = *sep)) c = ' ';
				*(p+klen) = c;
				memzcpy(p+klen+1,p1,len);
				cl_set_parm_char(pInfoParmW,p,klen+1+len);
			}
			else memzcpy(p,p1,len);
			if (giOpt & 0x01) {			/* Column or Item */
				parm = p + klen + len + 1;
				if ((iRc=argc=akxtgetargvns2(p,len,argv+3,maxcol,parm,len+1+maxcol,sep,sep_opt)) < 0)
					goto err;
/*
printf("sort: i=%d argc=%d argv[3]=[%s]\n",i,argc,argv[3]);
*/
				for (j=0;j<giNPos;j+=2) {
					if ((opt=giPos[j+1]) & 0x06) {
						col = giPos[j]+2;
						p1 = argv[col];
/*
printf("sort: i=%d j=%d col=%d ord=%d\n",i,j,col,giPos[j+1]);
*/
						if (_conv_n(p1,strlen(p1),col,argv,at,opt) < 0) {
							iRc = -1008;
							goto err;
						}
					}
				}
			}
			else if (giNPos > 0) {
				col = 2;
				for (j=0;j<giNPos;j+=3) {
					pos = giPos[j] - 1;
					if ((opt=giPos[j+2]) & 0x06) {
						posl = giPos[j+1];
						if (!posl) posl = len - pos;
						if (pos >= len) posl = 0;
/*
printf("sort: i=%d j=%d pos=%d posl=%d\n",i,j,pos,posl);
*/
						if (_conv_n(p1,posl,++col,argv,at,opt) < 0) {
							iRc = -1009;
							goto err;
						}
					}
					else argv[2] = p;
				}
			}
			else {
				argv[2] = p;
			}
			n++;
		}
	}
	if (!giOpt & 0x01) {
		col = 0;
		for (j=0;j<giNPos;j+=3) {
			pos = giPos[j+2];
			if (pos & 0x06) giPos[j+1] = ++col;
/*
printf("sort: j=%d pos=%d posl=%d\n",j,pos,giPos[j+1]);
*/
		}
	}

	/* ソートする */
	if (giOpt & 0x01) qsort(pargv,n,sizeof(char *),_sort_func_col);
	else qsort(pargv,n,sizeof(char *),_sort_func_pos);

	/* ソート結果を返却変数テーブルに設定する */
	index = tIndex_to.index;
	ix = index[3];
/*
printf("sort: n=%d ix=%d pTBL_to=%08x\n",n,ix,pTBL_to);
*/
	for (i=0;i<n;i++,ix++) {
		pInfoParm = cl_get_array_and_var_ent(&tIndex_to,pTBL_to,ix);
		if (pInfoParm) {
			if (iRc=cl_gx_rep_info_set(pInfoParm,*pargv[i],1)) goto err2;
		}
	}
	iRc = 0;
	memcpy(pWork,&n,sizeof(int));
 err:
				/* %s: %d 件目のデータでエラー(%d)が発生しました。 */
	if (iRc < 0) ERROROUT3(FORMAT(537),_fn_,n+1,iRc);
 err2:
	return iRc;
}
