
/*
 * CINELERRA
 * Copyright (C) 2006 Andraz Tori
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include "asset.h"
#include "bchash.h"
#include "condition.h"
#include "confirmsave.h"
#include "edits.h"
#include "edl.h"
#include "edlsession.h"
#include "file.h"
#include "filesystem.h"
#include "filexml.h"
#include "language.h"
#include "localsession.h"
#include "mainerror.h"
#include "mainsession.h"
#include "mutex.h"
#include "mwindowgui.h"
#include "mwindow.h"
#include "exportedl.h"
#include "tracks.h"
#include "transition.h"
#if defined (__FreeBSD__) || defined (__NetBSD__)
#include <libgen.h>
#endif
#include <ctype.h>
#include <string.h>

ExportEDLAsset::ExportEDLAsset(MWindow *mwindow, EDL *edl)
{
	this->mwindow = mwindow;
	this->edl = edl;

	path[0] = 0;
	edl_type = EDLTYPE_CMX3600;
	track_number = -1;
}

ExportEDLAsset::~ExportEDLAsset()
{
}

void ExportEDLAsset::double_to_CMX3600(double seconds, double frame_rate, char *str)
{
	char tmp[20];
	Units::totext(tmp,
			seconds,
			TIME_HMSF,
			0, // sample_rate ... unnecessary
			frame_rate,
			0); // frames per foot
	if ((int)(seconds / 3600) <= 9)
	{
		str[0]='0';
		strcpy(str+1, tmp);
	} else
	{
		strcpy(str, tmp);
	}

//	str[8]='.';

	//sprintf(str, "%02d:%02d:%02d:%02d", hour, minute, second, hundredths);
}

int ExportEDLAsset::edit_to_timecodes(Edit *edit,
	char *sourceinpoint, char *sourceoutpoint,
	char *destinpoint, char *destoutpoint,
	char *reel_name)
{
	Track *track = edit->track;
	double frame_rate = edit->track->edl->session->frame_rate;

	double edit_sourcestart;
	double edit_sourceend;
	double edit_deststart;
	double edit_destend;
	double timecode_offset;
	
	// timecode_offset in seconds
	timecode_offset = edit->track->edl->session->timecode_offset;
	//printf("tc offset %f, \n", timecode_offset);
	
	
	if(!strcmp(reel_name,""))
	strcpy(reel_name, "   BL   ");
	edit_sourcestart = track->from_units(edit->startsource);
	edit_sourceend = track->from_units(edit->length + edit->startsource);
	
	edit_deststart = track->from_units(edit->startproject);
	edit_destend = track->from_units(edit->startproject + edit->length);

	double_to_CMX3600(edit_sourcestart, frame_rate, sourceinpoint);
	double_to_CMX3600(edit_sourceend, frame_rate, sourceoutpoint);
	double_to_CMX3600(edit_deststart + timecode_offset, frame_rate, destinpoint);
	double_to_CMX3600(edit_destend + timecode_offset, frame_rate, destoutpoint);

	return 0;
}


void ExportEDLAsset::export_it()
{
	FILE *fh;
	fh = fopen(path, "w+");
	if( !fh ) {
		eprintf("unable to open file: %s", path);
		return;
	}

// We currently only support exporting one track at a time
// Find the track...
	int serial = 0;
	Track *track;
	for(track = edl->tracks->first;
		track;
		track = track->next)
	{
		if (serial == track_number)
			break;
		serial ++;
	}


	int last_dissolve = 1;

	if (edl_type == EDLTYPE_CMX3600)
	{

		// TODO: Find docs about exact header for CMX3600
		// https://xmil.biz/EDL-X/CMX3600.pdf
		double frame_rate = edl->session->frame_rate;
		int frame_rate_int = (int)frame_rate;
		char proj_title[BCTEXTLEN];
		strcpy(proj_title,basename(mwindow->session->filename));
		fprintf(fh, "TITLE: %s fps: %f\n", proj_title, frame_rate);
		switch(frame_rate_int) {
		case 24:
		case 25:
		case 50:
		case 60:
		case 30:
		{
		if (frame_rate - frame_rate_int < 0.001)
		fprintf(fh, "FCM: NON-DROP FRAME\n"); // fixme: select depending on fps
		break;
		}
		default:
		{
		if ((frame_rate - frame_rate_int) > 0.001)
		fprintf(fh, "FCM: DROP FRAME\n");
		}
		}
		// newline after FCM
		fprintf(fh, "\n");
		
		int colnum = 1;


		for (Edit *edit = track->edits->first;
			edit;
			edit = edit->next)
		{
		
		// max number of entries in cmx3600
		if (colnum > 999)
		return;
		
			char reel_name[BCTEXTLEN];
			char avselect[5];
			char edittype[5] = "C   ";
			char cutinfo[4] = "   ";
			char sourceinpoint[12];
			char sourceoutpoint[12];
			char destinpoint[12];
			char destoutpoint[12];
			
			char filename[1024];
			if (edit->asset)
			strcpy(filename,basename(edit->asset->path));
			
			if(!edit->asset)
			strcpy(reel_name,"BL  ");
			else
			strcpy(reel_name,"AX  ");
			
			if (track->data_type == TRACK_AUDIO)
				strcpy(avselect, "A   ");
			else
				strcpy(avselect, "V   ");

			//if (edit->transition)
			//	printf("title: %s, length: %i\n", edit->transition->title, edit->transition->length);
			if (edit->transition && !strcmp(edit->transition->title, "Dissolve"))
			{
				char last_sourceout[12];
				edit_to_timecodes(edit->previous, sourceinpoint, last_sourceout, destinpoint, destoutpoint, reel_name);
				edit_to_timecodes(edit, sourceinpoint, sourceoutpoint, destinpoint, destoutpoint, reel_name);

				if (last_dissolve)
				{
					fprintf(fh, "%03d %8s %s %4s %3s", colnum, reel_name, avselect, edittype, cutinfo);
					fprintf(fh, " %s %s", last_sourceout, last_sourceout);
					fprintf(fh, " %s %s", destinpoint, destinpoint);
					fprintf(fh,"\n");
					if(edit->asset)
					fprintf(fh,"* FROM CLIP NAME: %s\n", filename);
				} else
				{
					colnum --;
				}
				edittype[0] = 'D';
				fprintf(fh, "%03d %8s %s %4s %03jd", colnum, reel_name, avselect, edittype, edit->transition->length);
				fprintf(fh, " %s %s", sourceinpoint, sourceoutpoint);
				fprintf(fh, " %s %s", destinpoint, destoutpoint);
				fprintf(fh,"\n");
				if(edit->asset)
				fprintf(fh,"* FROM CLIP NAME: %s\n", filename);
				last_dissolve = 1;
			} else
			{
				edit_to_timecodes(edit, sourceinpoint, sourceoutpoint, destinpoint, destoutpoint, reel_name);
				fprintf(fh, "%03d %8s %s %4s %3s", colnum, reel_name, avselect, edittype, cutinfo);
				fprintf(fh, " %s %s", sourceinpoint, sourceoutpoint);
				fprintf(fh, " %s %s", destinpoint, destoutpoint);
				fprintf(fh,"\n");
				if(edit->asset)
				fprintf(fh,"* FROM CLIP NAME: %s\n", filename);
				last_dissolve = 0;
			}

			colnum ++;

		}
		
		fprintf(fh, "\n");
		
		// file end for final cut pro 1.2.5 ?
		fprintf(fh, "\x0D");
		fprintf(fh, "\x0A");
		fprintf(fh, "\x1A");
		fprintf(fh, "\x1A");

	}

	fclose(fh);


}



int ExportEDLAsset::load_defaults()
{
	mwindow->defaults->get("EDLEXPORT_PATH", path);
	mwindow->defaults->get("EDLEXPORT_TYPE", edl_type);
	mwindow->defaults->get("EDLEXPORT_TRACKNUMBER", track_number);
	//load_mode = mwindow->defaults->get("RENDER_LOADMODE", LOADMODE_NEW_TRACKS);


	return 0;
}

int ExportEDLAsset::save_defaults()
{
	mwindow->defaults->update("EDLEXPORT_PATH", path);
	mwindow->defaults->update("EDLEXPORT_TYPE", edl_type);
	mwindow->defaults->update("EDLEXPORT_TRACKNUMBER", track_number);
	return 0;
}




ExportEDLItem::ExportEDLItem(MWindow *mwindow)
 : BC_MenuItem(_("Export EDL..."), "Shift-E", 'E')
{
	this->mwindow = mwindow;
	set_shift(1);
}

int ExportEDLItem::handle_event()
{
	mwindow->exportedl->start_interactive();
	return 1;
}





ExportEDL::ExportEDL(MWindow *mwindow)
 : Thread(0, 0, 0)
{
	this->mwindow = mwindow;
//	package_lock = new Mutex("ExportEDL::package_lock");
//	counter_lock = new Mutex("ExportEDL::counter_lock");
//	completion = new Condition(0, "ExportEDL::completion");
//	progress_timer = new Timer;
}

ExportEDL::~ExportEDL()
{
//	delete package_lock;
//	delete counter_lock;
//	delete completion;
///	if(preferences) delete preferences;
//	delete progress_timer;
}

void ExportEDL::start_interactive()
{
	if(!Thread::running())
	{
		Thread::start();
	}
}

void ExportEDL::run()
{
	int result = 0;
	exportasset = new ExportEDLAsset(mwindow, mwindow->edl);

	exportasset->load_defaults();

// Get format from user
		result = 0;
		int filesok;

		do {
		// FIX
			filesok = 0;
			exportedl_window = new ExportEDLWindow(mwindow, this, exportasset);
			exportedl_window->create_objects();
			result = exportedl_window->run_window();
			if (! result) {
				// add to recentlist only on OK
				// Fix "EDL"!
				exportedl_window->path_recent->add_item("EDLPATH", exportasset->path);
			}
			exportasset->track_number = exportedl_window->track_list->get_selection_number(0, 0);

			delete exportedl_window;
			exportedl_window = 0;
			if (!result)
			{
				ArrayList<char*> paths;

				paths.append(exportasset->path);
				filesok = ConfirmSave::test_files(mwindow, &paths);
			}

		} while (!result && filesok);
	mwindow->save_defaults();
	exportasset->save_defaults();

// FIX
	if(!result) exportasset->export_it();


	delete exportasset;

}

#define WIDTH xS(410)
#define HEIGHT yS(400)

static const char *default_list_titles[] = {
	N_("No."),
	N_("Track name")
};

static int default_list_widths[] = {
	40,
	200
};


ExportEDLWindow::ExportEDLWindow(MWindow *mwindow, ExportEDL *exportedl, ExportEDLAsset *exportasset)
 : BC_Window(_(PROGRAM_NAME ": Export EDL"),
 	mwindow->gui->get_screen_w(1, 0) / 2 - WIDTH / 2,
	mwindow->gui->get_root_h(1) / 2 - HEIGHT / 2,
 	WIDTH, HEIGHT, (int)BC_INFINITY, (int)BC_INFINITY, 0, 0, 1)
{
	this->mwindow = mwindow;
	this->exportasset = exportasset;
// *** CONTEXT_HELP ***
 	context_help_set_keyword("Export to EDL");
	for( int i=0; i<2; ++i ) {
		list_titles[i] = _(default_list_titles[i]);
		list_widths[i] = xS(default_list_widths[i]);
	}
}

ExportEDLWindow::~ExportEDLWindow()
{
//	delete format_tools;
//	delete loadmode;
}


void ExportEDLWindow::create_objects()
{
	int xs5 = xS(5);
	int ys5 = yS(5), ys25 = yS(25);
	lock_window("ExportEDLWindow::create_objects");
	int x = xs5, y = ys5;
	add_subwindow(new BC_Title(x, y,
			_("Select a file to export to:")));
	y += ys25;

	add_subwindow(path_textbox = new ExportEDLPathText(x, y, this));
	x += xS(300);
	path_recent = new BC_RecentList("EDLPATH", mwindow->defaults,
					path_textbox, 10, x, y, xS(300), yS(100));
	add_subwindow(path_recent);
// FIX
	path_recent->load_items("EDLPATH");

	x += xS(24);
	add_subwindow(path_button = new BrowseButton(
		mwindow->theme, this, path_textbox, x, y - 4, exportasset->path,
		_("Output to file"), _("Select a file to write to:"), 0));

	y += xS(34);
	x = xs5;
	add_subwindow(new BC_Title(x, y, _("Select track to be exported:")));
	y += ys25;


	items_tracks[0].remove_all_objects();
	items_tracks[1].remove_all_objects();
	int serial = 0;
	if (exportasset->track_number == -1)
		exportasset->track_number = 0;
	for(Track *track = mwindow->edl->tracks->first;
		track;
		track = track->next)
	{

		char tmp[16];
		sprintf(tmp, "%i\n", serial+1);

		BC_ListBoxItem *listitem = new BC_ListBoxItem(tmp);
		if (serial == exportasset->track_number)
			listitem->set_selected(1);
		items_tracks[0].append(listitem);
		items_tracks[1].append(new BC_ListBoxItem(track->title));
		serial ++;

	}


	add_subwindow(track_list = new ExportEDLWindowTrackList(this, x, y, xS(400), yS(200)));

	y += 5 + track_list->get_h();
	add_subwindow(new BC_Title(x, y, _("Currently only CMX 3600 format is supported")));


	add_subwindow(new BC_OKButton(this));
	add_subwindow(new BC_CancelButton(this));
	show_window();
	unlock_window();
}


ExportEDLPathText::ExportEDLPathText(int x, int y, ExportEDLWindow *window)
 : BC_TextBox(x, y, xS(300), 1, window->exportasset->path)
{
	this->window = window;
}
ExportEDLPathText::~ExportEDLPathText()
{
}
int ExportEDLPathText::handle_event()
{
	strcpy(window->exportasset->path, get_text());
//	window->handle_event();
	return 1;
}

ExportEDLWindowTrackList::ExportEDLWindowTrackList(ExportEDLWindow *window,
	int x, int y, int w, int h)
 : BC_ListBox(x, y, w, h, LISTBOX_TEXT,
		window->items_tracks,
		window->list_titles,
		window->list_widths,
		2)
{
	this->window = window;
}

int ExportEDLWindowTrackList::handle_event()
{
//	window->exportasset->track_number = get_selection_number(0, 0);
//	printf("aaaaa %i\n", window->exportasset->track_number );
//	window->set_done(0);
	return 1;
}

