#include "seaview.h"
#include <FL/Fl_Round_Button.H>
#include <FL/Fl_Check_Button.H>
#include <FL/Fl_Return_Button.H>
#include <FL/Fl_Choice.H>

void concatenate_dialog(SEA_VIEW *view);
static void cancel_callback(Fl_Widget *, void *);
void rank_name_callback( Fl_Widget *o, void *data);
void do_concatenate_callback( Fl_Widget *ob, void *data);


static Fl_Round_Button *by_name;
static Fl_Choice *choice;
static int 	interrupted;
static Fl_Check_Button *addgaps;

void concatenate_dialog(SEA_VIEW *view)
{
	Fl_Window *w;
	w = new Fl_Window(305, 160);
	choice = new Fl_Choice(130,10,170, 20, "Source alignment");
	choice->align(FL_ALIGN_LEFT);
	Fl_Window *w2 = Fl::first_window();
	int count = 0;
	while(w2 != NULL) {
		const char *wclass = w2->xclass();
		if(w2 != view->dnawin && wclass != NULL && strcmp(wclass, SEAVIEW_WINDOW) == 0) {
			choice->add(w2->label());
			Fl_Menu_Item *menu = (Fl_Menu_Item *)choice->menu();
			(menu + count)->user_data(w2->user_data());
			count++;
			}
		w2 = Fl::next_window(w2);
	   }
	if(choice->size() <= 1) {
		w->end();
		delete w;
		fl_alert("Concatenation requires more than one alignment window");
		return;
		}
	choice->value(0);
	static char title[100];
	sprintf(title, "Target alignment: %s", view->dnawin->label());
	Fl_Box *target = new Fl_Box(10, 40, w->w() - 20, 20, title);
	target->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
	Fl_Group *g = new Fl_Group(0, 70, w->w(), 40);
	by_name = new Fl_Round_Button(10, 75, 80, 20, "by name");
	by_name->value(1);
	by_name->type(FL_RADIO_BUTTON);
	by_name->callback(rank_name_callback, NULL);
	Fl_Round_Button *rank = new Fl_Round_Button(100, 75, 80, 20, "by rank");
	rank->type(FL_RADIO_BUTTON);
	rank->callback(rank_name_callback, NULL);
	g->end();
	addgaps = new Fl_Check_Button(10, 100, 100, 20, "add gaps");
	Fl_Button *cancel = new Fl_Button(10, 125, 50, 20, "Cancel");
	cancel->callback(cancel_callback, NULL);
	Fl_Return_Button *ok = new Fl_Return_Button(w->w() - 60, 125, 50, 20, "OK");
	ok->callback(do_concatenate_callback, view);
	w->end();
	w->callback(cancel_callback, NULL);
	w->show();
#ifndef MICRO
	w->hotspot(w);
#endif
	interrupted = FALSE;
	while(!interrupted) Fl::wait();
	w->hide();
	Fl::delete_widget(w);
}

static void cancel_callback( Fl_Widget *ob, void *data)
{
	interrupted = TRUE;
}

void rank_name_callback( Fl_Widget *o, void *data)
{
	if(o == by_name) addgaps->activate(); 
	else {
		addgaps->value(0);
		addgaps->deactivate();
	}
}

void do_concatenate_callback( Fl_Widget *ob, void *data)
{
	int i, j, l, *found;
	char *gaps;
	SEA_VIEW *target = (SEA_VIEW *)data;
	
	interrupted = TRUE;
	i = choice->value();
	Fl_Menu_Item *item = (Fl_Menu_Item *)choice->menu() + i;
	SEA_VIEW *source = (SEA_VIEW *)item->user_data();
	//concatenate target = target + source
	if(by_name->value()) {//concatenation by name
		if(addgaps->value()) {
			l = FL_max(target->seq_length, source->seq_length);
			gaps = (char *)malloc(l + 1);
			memset(gaps, '-', l);
			found = (int *)calloc(target->tot_seqs + source->tot_seqs, sizeof(int));
			}
		for(i = 0; i < source->tot_seqs; i++) {
			for(j = 0; j < target->tot_seqs; j++) if(strcmp(source->seqname[i], target->seqname[j]) == 0) break;
			if(j >= target->tot_seqs) {//seq in source absent from target
				if( addgaps->value() == 0 ) continue;
				//add a gap-only sequence to target
				add_seq_to_align(target, source->seqname[i], gaps, target->seq_length);
				j = target->tot_seqs - 1;
				if(source->comments[i] != NULL) target->comments[j] = strdup(source->comments[i]);
				}
			l = target->each_length[j] + source->each_length[i];
			target->sequence[j] = (char *)realloc(target->sequence[j], l + 1);
			memcpy(target->sequence[j] + target->each_length[j], source->sequence[i], source->each_length[i]);
			target->sequence[j][l] = 0;
			if(addgaps->value()) found[j] = TRUE;
			}
		if(addgaps->value()) {
			for(j = 0; j < target->tot_seqs; j++) {
				if(found[j]) continue;
				//seqs from target only are concatenated with a gap-only sequence
				l = target->each_length[j] + source->seq_length;
				target->sequence[j] = (char *)realloc(target->sequence[j], l + 1);
				memset(target->sequence[j] + target->each_length[j], '-', source->seq_length);
				target->sequence[j][l] = 0;
				}
			free(gaps); 
			free(found); 
			}
		}
	else {//concatenation by rank
		for(i = 0; i < source->tot_seqs; i++) {
			if(i >= target->tot_seqs) break;
			l = strlen(target->sequence[i]) + strlen(source->sequence[i]);
			target->sequence[i] = (char *)realloc(target->sequence[i], l + 1);
			strcat(target->sequence[i], source->sequence[i]);
			}
		}
	char *oldname = strdup(target->masename);
	free(target->masename);
	free(target->each_length);
	for(i = 0; i < target->tot_seqs; i++) free(target->col_rank[i]);
	free(target->col_rank);
	init_dna_scroller(target, target->tot_seqs, oldname, target->protein, target->header);	
	free(oldname);
	set_seaview_modified(target, TRUE);
}

