/****************************************
*					*
*   Copyright(C) 2010 gp-hss.		*
*	         ALL rights reserved.   *
*					*
*        http://fgp.gg-blog.com/	*
*					*
****************************************/

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define SetSeek(fp) fseek(fp, 0L, SEEK_SET)			//ファイル位置をファイルの最初に戻すマクロ
#define NamePos 15L						//ファイル名が始まる位置

int GetFileNum(void);						//動画ファイルの数を取得
int GetFileNumSub(FILE *);					//動画ファイル数を取得
char *InputFileName(int *, unsigned int *);			//ファイル名を取得
unsigned int GetFileNameSize(FILE *);				//ファイル名のサイズを取得
short CheckEnd(char, FILE *);					//ファイル名の終端判定
short CheckFileExist(const char *, unsigned int);		//動画ファイルの存在確認
void DelPic(const char *, unsigned int);			//サムネイルの消去
void CrsLine(FILE *);						//存在しなかったファイルを含む行を削除

int main(void)
{
	int line = 1, file_num = 0;		//ファイル名のあった行, 動画ファイルの数
	unsigned int fn_size;			//ファイル名の長さを格納
	FILE *crs_line_file;			//消す行を記憶させておくファイルへのポインタ
	short exist_crs_line = 0;		//消す行の有無を記憶しておく
	int i;					//ループカウンタ


	/*ファイル数の取得*/
	file_num = GetFileNum();
	printf("リストから読み取れるファイルの数 : %d\n\n", file_num);


	/*"a"モードでは指定ファイルが存在しない場合、自動的に新規作成してくれるので普通NULLが返ってくることはない*/
	crs_line_file = fopen("tmp_line.txt", "a");
	if(crs_line_file == NULL) {
		fprintf(stderr, "何らかのエラーが発生しました。\n申し訳ございませんが処理を終了します。\n");
		exit(-1);
	}


	/*ファイルの数だけ確認を行う*/
	for(i = 1; i <= file_num + 1; i++) {
		char *fn;				//ファイル名へのポインタの一時変数
		if((fn = InputFileName(&line, &fn_size)) == (char *)NULL)
			break;
		if(CheckFileExist(fn, fn_size) == 1) {
			//ファイルの存在がなければそのファイル名を含んだ行を記憶しておく
			fprintf(crs_line_file, "%d\n", line - 1);
			if(exist_crs_line == 0)
				exist_crs_line++;
		}
	}


	if(exist_crs_line != 0) {
		fclose(crs_line_file);			//一度ファイルを閉じ、読み取りモードでもう一度開く
		crs_line_file = fopen("tmp_line.txt", "r");
		CrsLine(crs_line_file);			//新規リストファイルを作成する
	} else
		printf("リストは正常です。\n整理すべき項目はありませんでした。\n");

	
	fclose(crs_line_file);				//tmp_line.txtへのファイルポインタを閉じる
	system("del tmp_line.txt");			//今後このファイルを参照することはないので削除
	exit(0);
}

int GetFileNum()
{
	FILE *fp_num;
	int num;

	fp_num = fopen("jw_flv_list.dat", "r");
	if(fp_num == NULL) {
		fprintf(stderr, "jw_flv_list.datが確認できませんでした。\n");
		fprintf(stderr, "jwmakelist バッチファイルと同じディレクトリにあるか確認してください。\n"); 
		exit(-1);
	}

	num = GetFileNumSub(fp_num);
	fclose(fp_num);
	return num;
}

int GetFileNumSub(FILE *fp)
{
	/*ファイルに含まれる改行文字を調べる*/
	int counter = 0;

	while(1) {
		char ch;
		if((ch = fgetc(fp)) == '\n')
			counter++;		//改行文字の合計 ＝ ファイルの数
		else if(ch == EOF)
			break;
	};					//ファイルの終端に到達したら処理を終了
	SetSeek(fp);				//ファイル位置表示子をファイルの最初に戻しておく

	return counter;
}

char *InputFileName(int *line, unsigned int *fn_size)
{
	static FILE *fp;			//ファイルストリームへのポインタ
	static char *filename;			//filename
	static short func_count = 0;		//関数の呼び出し有無
	short i, j;				//ループカウンタ, ループカウンタ
	char ch;				//一時変数


	/*jw_flv_list.datをバイナリモードでオープン*/
	if(func_count == 0) {
		fp = fopen("jw_flv_list.dat", "rb");
		if(fp == NULL) {
			fprintf(stderr, "jw_flv_list.datが確認できませんでした。\n");
			fprintf(stderr, "jwmakelist バッチファイルと同じディレクトリにあるか確認してください。\n"); 
			exit(-1);
		}
	}

	if(fgetc(fp) == EOF) {
		fclose(fp);
		return (char *)NULL;
	} else
		fseek(fp, -1L, SEEK_CUR);

	/*ファイル名の長さを取得*/
	*fn_size = GetFileNameSize(fp);

	/*２回目以降はfilenameの指す記憶域を開放しておく*/
	if(func_count >= 1)
		free(filename);

	/*ファイル名を記憶する記憶域を確保*/
	filename = (char *)calloc(*fn_size + 1, sizeof(char));
	if(filename == NULL) {
		fprintf(stderr, "ファイル名が長すぎるためメモリの確保に失敗しました。\n");
		fprintf(stderr, "またはメモリ容量が少なすぎるため失敗した恐れがあります。\n");
		exit(-1);
	}

	/*ファイル名を取得*/
	fseek(fp, NamePos, SEEK_CUR);
	fread(filename, sizeof(char), *fn_size, fp);
	filename[*fn_size] = '\0';

	/*ファイル位置表示子の移動*/
	do {
		ch = fgetc(fp);
	} while (ch != '\n' && ch != EOF);	//次の行の最初にファイル位置表示子を置いておく
	(*line)++;				//行を記憶。現在取得したファイル名を含む行は line - 1 で求める


	if(func_count == 0)
		func_count++;

	printf("現在読み取ったファイル名 : %s\n\n", filename);
	return filename;			//ファイル名のアドレスを返し外部から参照する
}

unsigned int GetFileNameSize(FILE *fp)
{
	fpos_t file_pos;			//ファイル位置表示子の現在地を格納
	fpos_t save_pos;			//ファイル位置表示子の記憶用

	fgetpos(fp, &save_pos);			//表示子の位置を記憶しておく
	
	while(1) {
		if(CheckEnd(fgetc(fp), fp) == 1)	//2バイト文字は表示子が二つ分動くことで読み込む
			break;
	}

	fgetpos(fp, &file_pos);			//表示子の現在地を取得
	fsetpos(fp, &save_pos);			//元の位置に戻しておく
	return (unsigned int)file_pos - NamePos - (unsigned int)save_pos;
}	

short CheckEnd(char f_ch, FILE *fp)
{
	/*</title>を目安にファイル名の終端を探す*/
	if(f_ch == '<') {
		char str[8];
		fpos_t save;
		fgetpos(fp, &save);			//表示子の位置の保存
		fread(str, sizeof(char), 8, fp);
		str[7] = '\0';
		if(strcmp(str, "/title>") == 0) {
			fsetpos(fp, &save);
			fseek(fp, -1L, SEEK_CUR);
			return 1;
		}
	}
	return 0;
}

short CheckFileExist(const char *filename, unsigned int size)
{
	FILE *fp_exist;
	char *file_path;

	/*ファイルへのパスを格納する記憶域を確保*/
	file_path = (char *)calloc(size + 9, sizeof(char));
	if(file_path == NULL) {
		fprintf(stderr, "メモリの確保に失敗しました。\n");
		exit(-1);
	}
	sprintf(file_path, "movie\\%s", filename);

	/*movieフォルダの中にdatに記入されていた動画ファイルが存在するか確認する*/
	fp_exist = fopen(file_path, "r");
	free(file_path);
	if(fp_exist == NULL) {
		printf("「%s」の存在が確認できませんでした。\n", filename);
		printf("この動画ファイルのサムネイルを削除します。\n");
		DelPic(filename, size);		//存在しない動画ファイルのサムネイルを削除
		return 1;			//開けなかったら存在しないということなので1返す
	}

	fclose(fp_exist);			//存在していたらファイルを閉じる
	return 0;
}

void DelPic(const char *filename, unsigned int size)
{
	char *path;

	path = (char *)calloc(size + 14, sizeof(char));
	if(path == NULL) {
		fprintf(stderr, "メモリの確保に失敗しました。\n");
		exit(-1);
	}
	sprintf(path, "del pic\\%s.jpg", filename);

	/*jpgファイルを削除する*/
	system(path);
	free(path);
}

void CrsLine(FILE *clf)
{
	FILE *ori_fp, *crs_fp;
	int now_line = 1, crs_line = 0;

	/*オリジナルのリストファイルを開く*/
	ori_fp = fopen("jw_flv_list.dat", "r");
	if(ori_fp == NULL) {
		fprintf(stderr, "jw_flv_list.dat が確認できませんでした。\n");
		fprintf(stderr, "jwmakelist バッチファイルと同じディレクトリにあるか確認してください。\n");
		exit(-1);
	}


	/*仮のリストファイルを新規作成し、開く*/
	crs_fp = fopen("tmp_list.txt", "a");
	if(crs_fp == NULL) {
		fprintf(stderr, "何らかのエラーが発生しました。\n申し訳ございませんが処理を終了します。\n");
		exit(-1);
	}


	/*"オリジナル" => "仮"に文字を出力していく*/
	printf("\nリストから存在しないファイルへの項目を削除します。\n");
	fscanf(clf, "%d", &crs_line);
	while(1) {
		//削除すべき行の文字の場合は読み込むだけで"仮"には出力しない
		if(now_line == crs_line) {
			if(fgetc(ori_fp) == '\n') {
				now_line++;
				fscanf(clf, "%d", &crs_line);
				printf("%d行目のリストを削除しました。\n\n", now_line - 1);
			}
		//削除しなくてもいい行の文字は読み込み、"仮"に出力
		} else {
			int ch;
			ch = fgetc(ori_fp);
			if(ch == EOF)		//読み込んだ文字がファイル終端文字であれば読み込みを終了
				break;
			fputc(ch, crs_fp);	//"仮"ファイルに文字を出力
			if(ch == '\n')		//改行文字を読み込めば現在の行を表す数値を１つ上げる
				now_line++;
		}
	}

	/*読み込み・出力が終了すれば開いていたファイルを閉じる*/
	fclose(ori_fp);
	fclose(crs_fp);

	printf("古いリストを消去して新しいリストを作成します。\n");
	system("del jw_flv_list.dat");				//オリジナルファイルを消去
	system("rename tmp_list.txt jw_flv_list.dat");		//"仮"ファイルをオリジナルファイル名にリネーム
	printf("リストの整理処理が完了しました。\n");
}