#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <dirent.h>

#define COMMAND_MAX_SIZE 512 //maximalni delka retezce, kterou je mozno nacist od uzivatele vcetne \0
extern int errno;

struct dir_tree {
	struct dir_tree * prev;
	struct dir_tree * next;
	struct dirent * file;
};

typedef enum {
	UNKNOWN,
	HELP,
	LS,
	CD,
	CAT,
	EXIT
} prikaz;

/**
 * Vraci cislo prikazu nacteneho od uzivatele. Pokud ma prikaz argument,
 * nacte se do parametru command.
 */
prikaz readcommand(char * command)
{
	prikaz navrat = UNKNOWN;
	printf("$ ");
	scanf("%s",command);
	
	if(!strcmp("help",command)) navrat = HELP;
	else if(!strcmp("ls",command)) navrat = LS;
	else if(!strcmp("dir",command)) navrat = LS;
	else if(!strcmp("exit",command)) navrat = EXIT;
	else if(!strcmp("quit",command)) navrat = EXIT;
	else if(!strcmp("cd",command)) navrat = CD;	
	else if(!strcmp("cat",command)) navrat = CAT;	
	
	if(navrat == CD || navrat == CAT) {
		// nactu argument
		scanf("%s",command);
	}
	else {
		// zadny argument
		command[0] = '\0';
	}
	return navrat;
}

// FUNKCE SPRACOVAVAJICI PRIKAZY
void command_help(struct dir_tree * rootdir, char * arg)
{
	printf("NÁPOVĚDA\n"
		"Program můžete ovládat následujícími příkazy:\n"
		"help		- vypíše tuto nápovědu\n"
		"ls             - vypíše název souboru\n"
		"cd <adresář>	- přejde do zadaného adresáře\n"
		"cat <soubor>	- vypíše zadaný soubor\n"
		"exit		- ukončí program\n"
		"\n");
}

/**
 *  nacte zdany adresar a ulozi jeho strukturu do spojoveho seznamu dir_tree
 */
void command_cd(struct dir_tree * rootdir,char * adresar)
{
	struct dir_tree * helpdir1;
	DIR *str_dir;
	struct dirent * d;

	// pokusime se zmenit aktualni adresar
	if(chdir(adresar)) {
		perror("chdir");
		return;
	}
	// pokud dir_tree obsahuje nejake polozky, uvolnime je
	while(rootdir->next != NULL)
	{
		helpdir1 = rootdir->next->next;
		free(rootdir->next->file);
		free(rootdir->next);
		rootdir->next = helpdir1;
	}
	
	// nacteni adresare
	str_dir = opendir(".");
	if(str_dir == NULL) {
		perror("opendir");
		return;
	}
	while(d = readdir(str_dir))
	{
		helpdir1 = (struct dir_tree *) malloc(sizeof(struct dir_tree));
		if(!helpdir1) {
			printf("Nedostatek paměti!\n");
			break;
		}
		helpdir1->file = (struct dirent *) malloc(sizeof(struct dirent));
		if(!helpdir1->file) {
			printf("Nedostatek paměti!\n");
			break;
		}

		helpdir1->prev = rootdir;
		helpdir1->next = NULL;
		*(helpdir1->file) = *d;
		rootdir->next = helpdir1;
		rootdir = rootdir->next;
		//printf("nacitam %s\n",helpdir1->file->d_name);
	}
	
	if(closedir(str_dir))
		perror("closedir");
}
/**
 * Vypise na obrazovku obsah aktualniho adresare
 * */
void command_ls(struct dir_tree * rootdir,char * arg)
{
	printf("type\tinode\tsize\tname\n");
	while(rootdir->next) {
		rootdir = rootdir->next;
		printf("%i\t%i\t%i\t%s\n",
			rootdir->file->d_type,
			rootdir->file->d_ino,
			rootdir->file->d_reclen,
			rootdir->file->d_name);
	}
}

void command_cat(struct dir_tree * rootdir,char * filename)
{
	FILE * f;
	char sbuffer[512];
	size_t nacteno;

	if(!(f = fopen(filename,"r")))
	{
		perror("fopen");
		return;
	}

	while(!feof(f))
	{
		if(!(nacteno = fread(sbuffer,sizeof(char),sizeof(sbuffer)-1,f)))
		{
			perror("fread");
			break;
		}
		sbuffer[nacteno] = '\0';
		printf("%s",sbuffer);
	}

	if(fclose(f))
		perror("fclose");
}

int main(void)
{
	struct dir_tree rootdir = {NULL,NULL,NULL};
	prikaz p;
	char command[COMMAND_MAX_SIZE];

	printf("Vítejte v du č.1!\n"
	       "----------------\n");

	command_cd(&rootdir,".");
	command_help(&rootdir, NULL);
	do {
		p = readcommand(command);
		switch(p) 
		{
			case HELP:
				command_help(&rootdir,command);
				break;
			case CD:
				command_cd(&rootdir,command);
				break;
			case LS:
				command_ls(&rootdir,command);
				break;
			case CAT:
				command_cat(&rootdir,command);
				break;
			case UNKNOWN:
			default:
				printf("Neznámý příkaz! Zadejte help pro nápovědu.\n");
				break;
			case EXIT:
				printf("Nashledanou!\n");
				break;
		}
	} while(p != EXIT);
	return 0;
}

