/*

dmove86 Version 2.00c
Copyright (c) 1993,94 Delmonta

dmove86.c -- メインルーチン

*/

#define	MAIN

#include<stdio.h>
#include<dos.h>
#include<stdlib.h>
#include<ctype.h>
#include<signal.h>
#include"dmove86.h"

/*-----------------------------------変数------------------------------------*/
static	unsigned	Pagenum,Lastnum;/* ページ数･最終ページのエントリ数 */
static	unsigned	Page=0,Pos=0;	/* 現在のページ番号とカーソル位置  */
static	unsigned	Selected=-1;	/* 選択され反転表示されている番号  */
static	int		Ischanged = 0;
/*---------------------------------------------------------------------------*/
static	int	isok(void)
{
	if	(!Ischanged)
		return 1;

rep:
	switch	(dm_errmes("\aデータを保存していません よろしいですか(y/n)"))
	{
	case 'N':
	case 'n':
	case '\033':
		return 0;
	case 'Y':
	case 'y':
		return 1;
	default:
		goto rep;
	}
}

/*---------------------------------画面表示----------------------------------*/
static	void	putfilename(p)		/* 画面にファイル名を表示          */
int		p;
{
	printf("\033[%d;%df ",p/6+3,(p%6)*13+1);

	if	(Page*96+p == Selected)
		printf("\033[7");	/* 最後の'm'はまだつけない */
	else
		printf("\033[0");

	if	(Dirtbl[Page*96+p]->filename[0]=='\xe5')
		printf("m::::::::.:::");
	else
	{
		int	i;

		if	(Dirtbl[Page*96+p]->attr & _A_SUBDIR)
			printf(";32m");		/* ディレクトリは緑 */
		else if	(Dirtbl[Page*96+p]->attr & _A_VOLID)
			printf(";35m");		/* ボリュームIDは紫 */
		else if	(Dirtbl[Page*96+p]->attr & _A_SYSTEM)
			printf(";31m");		/* システムファイルは赤 */
		else
			printf(";37m");		/* そのほかは白 */

		for	(i=0 ; i<8 ; i++)
		{
			if	(i==0 && Dirtbl[Page*96+p]->filename[0]==5)
				putchar('\xe5');
			else
				putchar(Dirtbl[Page*96+p]->filename[i]);
		}

		putchar('.');

		for	(i=0 ; i<3 ; i++)
			putchar(Dirtbl[Page*96+p]->extname[i]);
	}
	printf(" \n\033[0;37m");
}

static	void	putpage(n)	/* ページ表示 */
int		n;		/* n!=0なら一度画面を消す */
{
	int		i;

	printf("\033[3;1f");

	if	(n)
		for	(i=0 ; i<16 ; i++)
			printf("\033[2K\n");

	for	(i=0 ; i<96 ; i++)
	{
		if	(Page==Pagenum-1 && i==Lastnum)
			break;
		else
			putfilename(i);
	}
}

void	putcursor(void)
{
static	int		oldx = -1,
			oldy = -1;

	if	(oldx != -1)
	{
		printf("\033[%d;%df",oldy+3,oldx*13+1);
		putchar(' ');
		printf("\033[%d;%df",oldy+3,oldx*13+13+1);
		putchar(' ');
	}

	oldx = Pos%6;
	oldy = Pos/6;

	printf("\033[%d;%df",oldy+3,oldx*13+1);
	putchar('<');
	printf("\033[%d;%df",oldy+3,oldx*13+13+1);
	putchar('>');
}

/*----------------------------カーソル移動とキー入力-------------------------*/
static	char	movecursor(flag)
int		flag;			/* ｶｰｿﾙ･ｽﾍﾟｰｽ･ESC以外を受け付けるか */
{
	int	c;

LOOP:
	putcursor();

	c = dm_getch();

	if	(c == '\3')
		endscreen();

	if	(c == '\x1a')
		endscreen();

	switch	(c)
	{
	case RIGHTKEY:
		Pos++;
		if	(Pos==96 || (Page==Pagenum-1 && Pos==Lastnum) )
			Pos=0;
		break;

	case LEFTKEY:
		if	(Pos==0)
		{
			if	(Page==Pagenum-1)
				Pos = Lastnum-1;
			else
				Pos = 95;
		}
		else
			Pos--;
		break;

	case UPKEY:
		if	(Pos>=6)
			Pos = Pos-6;
		break;

	case DOWNKEY:
		if	(Pos>=96-6 || (Page==Pagenum-1 && Pos+6>=Lastnum) )
			;	/* Pos>=Lastnum-6では、Lastnum-6<0となって   */
		else		/* Posがunsignedの為正確に判断できない場合有 */
			Pos = Pos+6;
		break;

	case '-':
		if	(Page>=1)
		{
			Page--;
			putpage(1);
		}
		break;

	case '+':
		if	(Page<Pagenum-1)
		{
			Page++;

			if	(Page==Pagenum-1 && Pos>=Lastnum)
				Pos = Lastnum-1;

			putpage(1);
		}
		break;

	case ' ':
		if	(Dirtbl[Page*96+Pos]->filename[0]!='.')
			return c;
		else
			dm_errmes("\".\"や\"..\"に対しては操作できません.\a");
		break;

	case '\033':
		return c;

	default:
		if	(flag)
			return c;

		break;
	}

	goto LOOP;
}

/*--------------------------------各コマンド---------------------------------*/
static	void	cmd_insert(void)
{
	int		i;
	struct DIRENTRY	far *d;

	if	((d=Dirtbl[Dirnum-1])->filename[0]=='\xe5')
	{
		for	(i=Dirnum-1 ; i>Page*96+Pos ; i--)
			Dirtbl[i] = Dirtbl[i-1];

		Dirtbl[Page*96+Pos] = d;
		Ischanged = 1;
		putpage(0);
	}
	else
		putchar('\a');
}

static	void	cmd_delete(void)
{
	int		i;
	struct DIRENTRY	far *d;

	if	((d=Dirtbl[Page*96+Pos])->filename[0]=='\xe5')
	{
		for	(i=Page*96+Pos ; i<Dirnum-1 ; i++)
			Dirtbl[i] = Dirtbl[i+1];

		Dirtbl[Dirnum-1] = d;
		Ischanged = 1;
		putpage(0);
	}
	else
		putchar('\a');
}
static	void	cmd_exchange(void)
{
	int		i;
	struct DIRENTRY	far *d;

	Selected = Page*96+Pos;

	putfilename(Pos);
	if	(movecursor(0)==' ' && Selected!=Page*96+Pos)
	{
		d = Dirtbl[Selected];
		Dirtbl[Selected] = Dirtbl[Page*96+Pos];
		Dirtbl[Page*96+Pos] = d;
		Ischanged = 1;
	}

	if	(Selected/96 == Page)
	{
		i = Selected%96;
		Selected = -1;
		putfilename(i);
	}
	else
		Selected = -1;

	putfilename(Pos);
}

static	void	cmd_sort(void)
{
	Selected = Page*96+Pos;
	putfilename(Pos);

	printf( "\033[19;1f\033[37mソート:終点を指定してください\n");

	if	(movecursor(0)==' ' && Selected!=Page*96+Pos)
	{
		unsigned int	s = Selected;
		unsigned int	e = Page*96+Pos;

		if	(s>e)
		{
			register unsigned int	a = e;
			e = s;
			s = a;
		}

		if	(dmsort(s,e))
			Ischanged = 1;
	}

	printf("\033[19;1f\033[2K");
	Selected = -1;
	putpage(0);
}

static	void	cmd_help(void)
{
	#define	EL	"\033[2K  "	/* 各行の行頭 */
	#define	AT	"\033[36m"	/* 水色 */
	#define	NO	"\033[37m"	/* 白に戻す */

	printf( "\033[3;1f"
	/* 0 */	EL "\n"
	/* 1 */	EL "                        コマンドリスト\n"
	/* 2 */	EL "\n"
	/* 3 */	EL AT "[SPACE]" NO "       2つのファイルの位置を交換します\n"
	/* 4 */	EL AT "H" NO "elp/" AT "[?]" NO "      この画面を表示します\n"
	/* 5 */	EL AT "D" NO "elete        空白を削除します\n"
	/* 6 */	EL AT "I" NO "nsert        空白を挿入します\n"
	/* 7 */	EL AT "R" NO "ename        ファイル名等を変更します\n"
	/* 8 */	EL AT "S" NO "ort          エントリをソートします\n"
	/* 9 */	EL AT "C" NO "hdir/" AT "[RET]" NO "   サブディレクトリの中に入ります\n"
	/* A */	EL AT "Q" NO "uit/" AT "[ESC]" NO "    親ディレクトリに戻ります\n"
	/* B */	EL AT "O" NO "riginal      編集をやり直します\n"
	/* C */	EL AT "W" NO "rite         ディスクに編集結果を書き込みます\n"
	/* D */	EL "\n"
	/* E */	EL "\n"
	/* F */	EL "\n");

	#undef	EL
	#undef	AT
	#undef	NO

	dm_errmes("何かキーを押してください.");
	putpage(1);
}
/*-------------------------------メインルーチン------------------------------*/
static	void	setglovalvar(struct DIRENTRY far **dirtbl,int dirnum)
{
	Dirtbl = dirtbl;

	Dirnum  = dirnum;
	Pagenum = dirnum/96;
	Lastnum = dirnum%96;

	if	(Lastnum)	Pagenum++;
	else			Lastnum = 96;

	Page = 0;
	Pos  = 0;

	Selected = -1;
	Ischanged = 0;
}

void	dmmenu(struct DIRENTRY far *parent)
{
	struct DIRENTRY	far *d;

	struct	SECTBL		*sectbl;
	auto	int		dirnum;
	struct	DIRENTRY far	**dirtbl;

reread:

	if	((dirtbl=readentry(parent,&sectbl,&dirnum))==NULL)
		return;

	setglovalvar(dirtbl,dirnum);
	putpage(1);

dmmenu_loop:

	switch	(movecursor(1))
	{
	case 'H':
	case 'h':
	case '?':
		cmd_help();
		break;
	case 'I':
	case 'i':
		cmd_insert();
		break;

	case 'D':
	case 'd':
		cmd_delete();
		break;

	case ' ':
		cmd_exchange();
		break;

	case 'S':
	case 's':
		cmd_sort();
		break;

	case 'R':
	case 'r':
		if	(Dirtbl[Page*96+Pos]->filename[0]=='\xe5')
			break;

		Selected = Page*96+Pos;
		putfilename(Pos);
		if	(dmrename(Selected))
			Ischanged = 1;

		Selected = -1;
		putfilename(Pos);
		break;

	case 'C':
	case 'c':
	case '\r':
		d = dirtbl[Page*96+Pos];

		if	(d->attr&_A_SUBDIR && d->filename[0]!='.')
		{
			int	ischanged_save = Ischanged;
			int	pagesave       = Page;
			int	possave        = Pos;

			dmmenu(d);
			setglovalvar(dirtbl,dirnum);

			Page = pagesave;
			Pos  = possave;
			Ischanged = ischanged_save;

			putpage(1);
		}
		break;

	case 'O':
	case 'o':
		if	(isok())
		{
			freesectbl(sectbl);
			free(dirtbl);
			goto reread;
		}
		break;
	case 'Q':
	case 'q':
	case '\033':
		if	(isok())
		{
			freesectbl(sectbl);
			free(dirtbl);
			return;
		}
		break;
	case 'W':
	case 'w':
		writedir(sectbl,dirtbl);
		Ischanged = 0;
		break;
	default:
		putchar('\a');
	}
	goto dmmenu_loop;
}
/*------------------------------スタートアップ-------------------------------*/
#ifdef	CTRLC_BUG	/* LSI C-86の無印Ver3.30はSIG_IGNの処理にバグがある */
	static	void	CTRLC_HANDLER(void)
	{
		signal(SIGINT,CTRLC_HANDLER);
	}
#else
	#define	CTRLC_HANDLER	SIG_IGN
#endif

int	main(int argc,char **argv)
{
	int	c;

	if	(argc != 2)
	{
	rep:
		printf("ドライブ名は:");
		c = dm_getch();
		if	(c=='\033')
			exit(0);
		else if	(!isalpha(c))
		{
			putchar('\n');
			goto rep;
		}

		putchar(c);
		putchar('\n');
	}
	else
		c = argv[1][0];

	Drive = toupper(c) - 'A';

	if	(Drive<0 || Drive>25)
	{	printf("不正なドライブ名です.\n");
		exit(2);
	}

	

	if	(getdpb() == -1)
	{	printf("指定されたドライブは存在しません.\n");
		exit(2);
	}

	Fat = getfat();

	if	(Fat == NULL)
	{	printf("FATの読み込みに失敗しました.\n");
		exit(3);
	}

	signal(SIGINT,CTRLC_HANDLER);

	mkscreen();
	dmmenu(NULL);
	endscreen();
}

void	endscreen(void)
{
	getdpb();	/* DOS内部のバッファを更新するため */

	printf( "\033[0v\033[>5l\033[2J"
		"DMOVE86を終了しました.\n");

	exit(0);
}

