/*
 * lieditor
 * image editor using terminal
 *
 * - saves into bmp format
 * - uses 8 colors
 * - works Linux terminals (in 80x24 window)
 * - references linuxstuff.h (http://halls-of-valhalla.org/beta/codes/linux-stuff-linuxstuff-h,77)
 *
 * author: László Ádám
 * e-mail: adam.laszlo.91@gmail.com
 * 2013. 2. december
 * version: 1.0
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linuxstuff.h"


//  global variables  //
int sizex,sizey; 
int color = BLACK;
char pressed;
char **map;
int x=0,y=0;
char continous = 0;

//  bottom  //
void bottom(){
	gotoxy(1,22);
	printf("move: w-a-s-d|\tdot: ENTER|\trubber: q|\tcolors: r|\ncontinous drawing: e|\nsave: m|\texit: l|");
}

//  rightside  //
void rightside(){
	int i;
	for (i = 3; i <= 17; i=i+2){
		gotoxy(72,i);
		backgroundcolor((i-3)/2);
		printf("   ");
		if ((i-3)/2 == color){
			defaultcolors();
			printf(" X");
		}
	}
	defaultcolors();
	if (continous){
		gotoxy(72,19);
		printf("cont.");
	}
	gotoxy(80,24);

}

//  changecolor  //
void changecolor(){
	color++;
	if (color == 8){
		color = 0;
	}
}

//  mapdrawer  //
void mapdrawer(){
	int i,k;
	gotoxy(1,1);
	for (i=0;i<sizey;i++){
		textcolor(BLACK);
		for (k=0;k<sizex;k++){
			backgroundcolor(map[i][k]);
			if (x == i && y == k){
				putchar('X');
			}else{
			putchar(' ');
			}
		}
		defaultcolors();
		putchar('|');
		putchar('\n');
	}
	for (i=0;i<=sizex;i++){
	putchar('-');
	}
}

//  save  //
int save(){
	char name[50];
	int scale = 10;
	int i,k,m,s, p;
	FILE *save;
	typedef struct{
	int sign[2];
	int size[4];
	int free[4];
	int bitmap_start[4];
	int inf_header[4];
	int x[4];
	int y[4];
	int show[2];
	int color_depth[2];
	int compress[4];
	int bitmap_size[4];
	int ppm_x[4];
	int ppm_y[4];
	int palette[4];
	int palette_colors[4];
	} bitmaps;
	bitmaps bitmap;
	clearscr();
	while(1){
		printf("- scale (recommended is 20): ");
		scanf("%d",&scale);
		if (scale < 1 || scale > 500){
			clearscr();
			printf("1 <= scale <= 500\n");
		}else{
			break;
		}
	}
	while(1){
	printf("- save as: ");
	scanf("%s",name);
	strcat(name,".bmp");
	if ((save=fopen(name,"r")) != NULL){
		clearscr();
		printf("- the file already exists\n\n");
		fclose(save);
	}else{
		// BM
		bitmap.sign[1]='M';
		bitmap.sign[0]='B';
		// size
		int size = 54+(sizex*scale+(sizex*scale)%4)*(sizey*scale+(sizey*scale)%4);
		bitmap.size[3]= size/(256*256*256);
		bitmap.size[2]=	(size%(256*256*256))/(256*256);
		bitmap.size[1]= (size%(256*256))/(256);
		bitmap.size[0]= size%256;
		// unused
		bitmap.free[3]=0;
		bitmap.free[2]=0;
		bitmap.free[1]=0;
		bitmap.free[0]=0;
		// offset for bitmap data
		bitmap.bitmap_start[3]=0;
		bitmap.bitmap_start[2]=0;
		bitmap.bitmap_start[1]=0;
		bitmap.bitmap_start[0]=54;
		// BID
		bitmap.inf_header[3]=0;
		bitmap.inf_header[2]=0;
		bitmap.inf_header[1]=0;
		bitmap.inf_header[0]=40;
		// x size
		int x_size = sizex*scale;
		bitmap.x[3]= x_size/(256*256*256);
		bitmap.x[2]= (x_size%(256*256*256))/(256*256);
		bitmap.x[1]= (x_size%(256*256))/(256);
		bitmap.x[0]= x_size%256;
		// y size
		int y_size = sizey*scale;
		bitmap.y[3]= y_size/(256*256*256);
		bitmap.y[2]= (y_size%(256*256*256))/(256*256);
		bitmap.y[1]= (y_size%(256*256))/(256);
		bitmap.y[0]= y_size%256;
		// number of color planes
		bitmap.show[1]=0;
		bitmap.show[0]=8;
		// bits per pixel
		bitmap.color_depth[1]=0;
		bitmap.color_depth[0]=24;
		// compression type
		bitmap.compress[3]=0;
		bitmap.compress[2]=0;
		bitmap.compress[1]=0;
		bitmap.compress[0]=0;
		// ??
		bitmap.bitmap_size[3]=0;
		bitmap.bitmap_size[2]=0;
		bitmap.bitmap_size[1]=0;
		bitmap.bitmap_size[0]=0;
		// pixel per meter x
		bitmap.ppm_x[3]=0;
		bitmap.ppm_x[2]=0;
		bitmap.ppm_x[1]=46;
		bitmap.ppm_x[0]=224;
		// pixel per meter y
		bitmap.ppm_y[3]=0;
		bitmap.ppm_y[2]=0;
		bitmap.ppm_y[1]=46;
		bitmap.ppm_y[0]=224;
		// blah blah
		bitmap.palette[3]=0;
		bitmap.palette[2]=0;
		bitmap.palette[1]=0;
		bitmap.palette[0]=0;
		// blah blah
		bitmap.palette_colors[3]=0;
		bitmap.palette_colors[2]=0;
		bitmap.palette_colors[1]=0;
		bitmap.palette_colors[0]=0;

		save=fopen(name,"wb");
		// write the blah blah into the file
		for (i=0;i<=1;i++){
		fputc(bitmap.sign[i],save);
		}
		for (i=0;i<=3;i++){
		fputc(bitmap.size[i],save);
		}
		for (i=0;i<=3;i++){
		fputc(bitmap.free[i],save);
		}
		for (i=0;i<=3;i++){
		fputc(bitmap.bitmap_start[i],save);
		}
		for (i=0;i<=3;i++){
		fputc(bitmap.inf_header[i],save);
		}
		for (i=0;i<=3;i++){
		fputc(bitmap.x[i],save);
		}
		for (i=0;i<=3;i++){
		fputc(bitmap.y[i],save);
		}
		for (i=0;i<=1;i++){
		fputc(bitmap.show[i],save);
		}
		for (i=0;i<=1;i++){
		fputc(bitmap.color_depth[i],save);
		}
		for (i=0;i<=3;i++){
		fputc(bitmap.compress[i],save);
		}
		for (i=0;i<=3;i++){
		fputc(bitmap.bitmap_size[i],save);
		}
		for (i=0;i<=3;i++){
		fputc(bitmap.ppm_x[i],save);
		}
		for (i=0;i<=3;i++){
		fputc(bitmap.ppm_y[i],save);
		}
		for (i=0;i<=3;i++){
		fputc(bitmap.palette[i],save);
		}
		for (i=0;i<=3;i++){
		fputc(bitmap.palette_colors[i],save);
		}
		// here is the image beging written into the file
		for (i=sizey-1;i>=0;i--){
		for (s = 1; s <= scale; s++){
		for (k=0;k<sizex;k++){
			for (p = 1; p <= scale; p++){
			switch(map[i][k]){
				case BLACK:
					putc(0,save);
					putc(0,save);
					putc(0,save);
					break;
				case RED:
					putc(0,save);
					putc(0,save);
					putc(255,save);
					break;
				case GREEN:
					putc(0,save);
					putc(255,save);
					putc(0,save);
					break;
				case YELLOW:
					putc(0,save);
					putc(255,save);
					putc(255,save);
					break;
				case BLUE:
					putc(255,save);
					putc(0,save);
					putc(0,save);
					break;
				case MAGENTA:
					putc(255,save);
					putc(0,save);
					putc(255,save);
					break;
				case CYAN:
					putc(255,save);
					putc(255,save);
					putc(0,save);
					break;
				case WHITE:
					putc(255,save);
					putc(255,save);
					putc(255,save);
					break;		
			}}
			for (m=1;m<=((sizex*scale)%4);m++){
				putc(0,save);
			}
		}
		}
		}
		fclose(save);
		clearscr();
		printf("saved\n");
		getchar();
		break;
	}
	}
return 0;
}

// drawer  //
int drawer(){		
	while(1){
	clearscr();
	mapdrawer();
	bottom();
	rightside();
	pressed=getcharacter();
	if (pressed == 'l'){
		system("clear");
		break;
	}
	if (pressed == 's'){
		if (x < sizey-1){
		x++;
		if (continous) map[x][y] = color;
		}
	}else if (pressed == 'w'){
		if (x > 0){
		x--;
		if (continous) map[x][y] = color;
		}
	}else if (pressed == 'a'){
		if (y > 0){
		y--;
		if (continous) map[x][y] = color;
		}
	}else if (pressed == 'd'){
		if (y < sizex-1){
		y++;
		if (continous) map[x][y] = color;
		}
	}else if (pressed == 10){
		map[x][y] = color;
	}else if (pressed == 'q'){
		map[x][y] = WHITE;
	}else if (pressed == 'm'){
		save();
		break;
	}else if (pressed == 'r'){
		changecolor();
	}else if (pressed == 'e'){
		continous = !continous;
		map[x][y] = color;
	}

	}
	return 0;
}

//  main  //
int main(void){
	int i,k;
	clearscr();
	while(1){
	printf("- image dimensions\n");
	printf("width: ");
	scanf("%d",&sizex);
	printf("height: ");
	scanf("%d",&sizey);
	if (sizex <3 || sizex > 70 || sizey <3 || sizey > 20){
		printf("- allowed dimensions: 3x3 -> 70x20\n\n");
	}else{
		break;
	}
	}
	getchar();

	map=(char**)malloc(sizey*sizeof(char*));
	for (i=0;i<sizex;i++){
		map[i]=(char*)malloc(sizex*sizeof(char));
	}
	for (i=0;i<sizey;i++){
		for (k=0;k<sizex;k++){
			map[i][k]=WHITE;
		}
	}

	drawer();
	
	for (i=0;i<sizex;i++){
		if (map[i] == NULL) free(map[i]);
	}	
	if (map == NULL) free(map);
	
	return 0;
}