#!/usr/bin/perl
use strict;

require Tk;
require Tk::Dialog;
require Tk::widgets;
require Tk::NoteBook;
require Tk::ProgressBar;

use Tk;
use Tk::Dialog;
use Tk::widgets;
use Tk::NoteBook;
use Tk::ProgressBar;


my $version = 0.49;

#
#configuring the display window
#

my $border_menu = 2;
my $color_back = "#FFFFFF";
my $color_menu_bar = "#AAAAAA";
my $color_mb_back = "#AAAAAA";
my $color_mb_aback = "#CCCCCC";
my $color_mb_fore = "#000000";
my $color_mb_dfore = "#CCCCCC";
my $color_printA = "#CCCCCC";
my $font_general = "Arial";
my $font_print = "Courier";
my $count_l = "count.txt";

#===> fontsize can be changed here
my $font_size_general = 10;#===> font for options
my $font_size_print = 10;#==> font for text boxes

# Main Window #{{{

#
#Creating the window
#

my $main = MainWindow->new(-background=> $color_back);
$main->minsize( qw(600 400));
$main->title("SAGE GenSuite");


my $main_font = $main->fontCreate("mfont", -family => $font_general,
	-weight => "normal",
	-size => $font_size_general);
my $print_font = $main->fontCreate("pfont", -family => $font_print,
	-size => $font_size_print);

$main->optionAdd("*font", "mfont");
$main->optionAdd("*borderWidth", 1);
$main->optionAdd("*tearOff", "false");


#}}}

# Menu Bar #{{{
#
my $menu_bar = $main->Frame(-relief => "flat",
	-borderwidth=> $border_menu
)->pack("-side"=> "top", 
	-fill=> "x");

my $file_mb = $menu_bar->Menubutton(-text=> "File",
	-relief => "flat"
)->pack(-side=> "left");

my $file_mb_open = $file_mb->cascade(-label => "Open");

my $file_mb_open_count = $file_mb_open->command(-label => "Import Tag Count",
	-command=> \&t1_load_pop);

my $file_mb_open_count = $file_mb_open->command(-label => "Import Count Expression",
	-command=> \&t1_load_pop_2);

my $file_mb_open_count = $file_mb_open->command(-label => "Tag Count",
	-command=> \&load_count);

my $file_mb_open_dt = $file_mb_open->command(-label => "Ditag List",
	-command=> \&t4_load_pop);

my $file_mb_save = $file_mb->cascade(-label => "Save");

my $file_mb_save_tc = $file_mb_save->cascade(-label => "Tag Counts");

my $file_mb_save_count = $file_mb_save_tc->command(-label => "Counts",
						   -command=> \&t1_save_c);

my $file_mb_save_expression = $file_mb_save_tc->command(-label => "Expression",
							  -command=> \&t1_save_e);

my $file_mb_save_trim = $file_mb_save->command(-label => "Trimmed Tags",
						 -command=> \&t2_save);

my $file_mb_save_di = $file_mb_save->cascade(-label => "Ditag");

my $file_mb_save_dil = $file_mb_save_di->command(-label => "List",
						   -command=> \&t3_save);

my $file_mb_save_dir = $file_mb_save_di->command(-label => "Report",
						   -command=> \&t3_save_r);

my $file_mb_save_cc = $file_mb_save->cascade(-label => "Concatamer");

my $file_mb_save_ccf = $file_mb_save_cc->command(-label => "FASTA",
						   -command=> \&t4_save);

my $file_mb_save_ccr = $file_mb_save_cc->command(-label => "Report",
						   -command=> \&t4_save_r);

$file_mb_save->separator();

my $file_mb_save_all = $file_mb_save->command(-label => "All",
	-command=> \&save_all);

$file_mb->separator();

$file_mb->command(-label => "Exit",
	-command=> sub {$main->destroy});

$file_mb->separator();

my $help_mb = $menu_bar->Menubutton(-text=> "Help",
)->pack(-side=> "right");

my $about_dialog = $main->Dialog(-title => "genSuite About",
	-text    => "GenSuite Version $version\nAn integrated tool for in-silico SAGE data creation\n(C) 2008 Samuel G. Guimaraes, Alan M. Durham & Arthur Gruber",
	-buttons => ["OK"]);

$help_mb->command(-label => "About",
	-activebackground=> $color_mb_aback);

$help_mb->entryconfigure("About", -command => [$about_dialog => "Show"]);

#}}}

# Notebook Tabs #{{{

my $book = $main->NoteBook(-background=> $color_back,
	-inactivebackground=> $color_mb_aback
)->pack(-fill=> "both",
	-expand=> "x");

$book->configure(-relief=> "flat");

my $tab1 = $book->add("TCG", 
	-label=> "Tag Count Generator");

$tab1->configure(-background=> $color_back);

my $tab2 = $book->add("TT",
	-label=> "Trim Tags");

$tab2->configure(-background=> $color_back);

my $tab3 = $book->add("C2D",
	-label=> "counts2ditags");

$tab3->configure(-background=> $color_back);

my $tab4 = $book->add("D2C",
	-label=> "ditags2concatamers");

$tab4->configure(-background=> $color_back);

#}}}

# tag_count_generator #{{{

my $t1_par1 = 18;
my $t1_par2 = 10;
my $t1_total = 100;
my $t1_dist_var = "uniform";
my $t1_dist_par1 = "-";
my $t1_dist_par2 = "-";
my $t1_dist_par3 = "1";
my $t1_save_file = "count.txt";
my $t1_import = "count.txt";
my $t1_import_2 = "expression.txt";
my $t1_mod_n = 5;
my $t1_mod_s = 6;
my $t1_mod_d = 1;
my $t1_gen_tag = 1;
my $t1_gen_dist = 1;
my $t1_gen_count = 1;
my $t1_mod = 0;
my $t2_printArea1;
my $t2_printArea2;
my $t3_printArea1;
my $t3_printArea2;
my $t3_printArea3;
my $cgig = 0;

if (&checkGIG) {
	print STDERR "GIG test ok...\n";
	$cgig = 1;
}
else {
	print STDERR "GIG test failed, deactivating GIG generation...\n";
}

sub t1_mod_window { #{{{

	$t1_mod = $main->Toplevel(-background=> $color_back);
	$t1_mod->minsize( qw(100 100));
	$t1_mod->title("modify");

	my $t1_mod_control = $t1_mod->Frame(-background=> $color_back #{{{
	)->pack(-side=> "top",
		-expand=> "both",
		-fill=> "both");

	my $t1_mod_ce = $t1_mod_control->Frame(-background=> $color_back
	)->pack(-side=> "left",
		-expand=> "both",
		-fill=> "both");

	my $t1_mod_ce_n = $t1_mod_ce->Frame(-background=> $color_back#{{{
	)->pack(-side=> "top",
		-fill=> "x",
		-anchor=> "w",
		-pady=> 2,
		-padx=> 5);

	my $t1_mod_ce_nl = $t1_mod_ce_n ->Label( -justify=>"left",
		-text=>"Number of changes parameter",
		-relief=>"flat", 
		-background => $color_back
	)->pack(-side=> "left",
		-anchor=>"w");

	my $t1_mod_ce_ne = $t1_mod_ce_n ->Entry(-borderwidth=>1,
		-background=> $color_back,
		-justify=> "left", 
		-relief=> "sunken", 
		-textvariable=> \$t1_mod_n,
		-width=> 5,
		-state=> "normal" 
	) ->pack(-side=>"right",
		-anchor=>"e");
#}}}

	my $t1_mod_ce_s = $t1_mod_ce->Frame(-background=> $color_back#{{{
	)->pack(-side=> "top",
		-fill=> "x",
		-anchor=> "w",
		-pady=> 2,
		-padx=> 5);

	my $t1_mod_ce_sl = $t1_mod_ce_s ->Label( -justify=>"left",
		-text=>"Mean",
		-relief=>"flat", 
		-background => $color_back
	)->pack(-side=> "left",
		-anchor=>"w");

	my $t1_mod_ce_se = $t1_mod_ce_s ->Entry(-borderwidth=>1,
		-background=> $color_back,
		-justify=> "left", 
		-relief=> "sunken", 
		-textvariable=> \$t1_mod_s,
		-width=> 5,
		-state=> "normal" 
	) ->pack(-side=>"right",
		-anchor=>"e");
#}}}

	my $t1_mod_ce_s = $t1_mod_ce->Frame(-background=> $color_back#{{{
	)->pack(-side=> "top",
		-fill=> "x",
		-anchor=> "w",
		-pady=> 2,
		-padx=> 5);

	my $t1_mod_ce_sl = $t1_mod_ce_s ->Label( -justify=>"left",
		-text=>"Standard deviation",
		-relief=>"flat", 
		-background => $color_back
	)->pack(-side=> "left",
		-anchor=>"w");

	my $t1_mod_ce_se = $t1_mod_ce_s ->Entry(-borderwidth=>1,
		-background=> $color_back,
		-justify=> "left", 
		-relief=> "sunken", 
		-textvariable=> \$t1_mod_d,
		-width=> 5,
		-state=> "normal" 
	) ->pack(-side=>"right",
		-anchor=>"e");

#}}}

#}}}

	my $t1_mod_b = $t1_mod->Frame(-background=> $color_back
	)->pack(-side=>"bottom");

	my $t1_mod_ok = $t1_mod_b->Button(-text=> "Ok",
		-command=> sub {&t1_modify;
			$t1_mod->destroy}
	)->pack(-side=>"left");

	my $t1_mod_cancel = $t1_mod_b->Button(-text=> "Cancel",
		-command=> sub {$t1_mod->destroy}
	)->pack(-side=>"left");


	$t1_mod->optionAdd("*font", "mfont");
	$t1_mod->optionAdd("*borderWidth", 1);
	$t1_mod->optionAdd("*tearOff", "false");

}

#}}}

my $t1_top = $tab1->Frame( -background=> $color_back #{{{
)->pack(-side=> "top",
	-fill => "x",
	-padx=> 5,
	-pady=> 5);

my $t1_left2t = $t1_top->Frame(-background=> $color_back,#{{{
	-width=> 150
)->pack(-side=> "left",
	-anchor=> "n",
	-pady=> 2,
	-padx=> 5);

my $t1_seq_size = $t1_left2t ->Label( -justify=>"left",
	-text=>"",
	-relief=>"flat", 
	-background => $color_back
)->pack(-side=>"top",
	-anchor=>"w");

my $t1_left1t1 = $t1_left2t->Frame(-background=> $color_back#{{{
)->pack(-side=> "top",
	-anchor=> "w",
	-pady=> 2,
	-padx=> 5);

my $t1_seq_size = $t1_left1t1 ->Label( -justify=>"left",
	-text=>"Total tag count",
	-relief=>"flat", 
	-background => $color_back
)->pack(-side=>"left",
	-anchor=>"w");

my $t1_p_seq_size = $t1_left1t1 ->Entry(-borderwidth=>1,
	-background=> $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t1_total,
	-width=> 5,
	-state=> "normal" 
) ->pack(-side=>"left",
	-anchor=>"e");
#}}}

my $t1_left2t1 = $t1_left2t->Frame(-background=> $color_back#{{{
)->pack(-side=> "top",
	-anchor=> "w",
	-pady=> 2,
	-padx=> 5);

my $t1_seq_size = $t1_left2t1 ->Label( -justify=>"left",
	-text=>"Sequence Size",
	-relief=>"flat", 
	-background => $color_back
)->pack(-side=> "left",
	-anchor=>"w");

my $t1_p_seq_size = $t1_left2t1 ->Entry(-borderwidth=>1,
	-background=> $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t1_par1,
	-width=> 5,
	-state=> "normal" 
) ->pack(-side=>"left",
	-anchor=>"e");
#}}}

my $t1_left2t2 = $t1_left2t->Frame(-background=> $color_back,#{{{
)->pack(-side=> "top",
	-anchor=> "w",
	-pady=> 2,
	-padx=> 5);

my $t1_seq_num = $t1_left2t2 ->Label( -justify=>"left",
	-text=>"Number of sequences",
	-relief=>"flat", 
	-background => $color_back
)->pack(-side=> "left",
	-anchor=>"w");

my $t1_p_seq_num = $t1_left2t2 ->Entry(-borderwidth=>1,
	-background=> $color_back,
	-justify=> "left", 
	-relief=> "sunken", 
	-textvariable=> \$t1_par2,
	-width=> 5,
	-state=> "normal" 
) ->pack(-side=>"left",
	-anchor=>"e");
#}}}

#}}}

my $t1_left4t = $t1_top->Frame(-background=> $color_back#{{{
    )->pack(-side=> "left",
	    -anchor=> "n",
	    -pady=> 2,
	    -padx=> 5);

my @t1_dist;

my $t1_mod_size = 9;
my $t1_dist_lab = $t1_left4t->Label(-text=> "Count distribution:",
				    -background=> $color_back,
    )->pack(-anchor=> "w");
$t1_dist[0] = $t1_left4t->Radiobutton(-text=> "Uniform",
				      -width=> $t1_mod_size,
				      -background=> $color_printA,
				      -value=> "uniform",
				      -command=> \&uni_cb,
				      -variable=> \$t1_dist_var
    )->pack(-anchor=> "w");
$t1_dist[1] = $t1_left4t->Radiobutton(-text=> "Normal",
				      -width=> $t1_mod_size,
				      -background=> $color_printA,
				      -value=> "normal",
				      -command=> \&nor_cb,
				      -variable=> \$t1_dist_var
    )->pack(-anchor=> "w");
$t1_dist[2] = $t1_left4t->Radiobutton(-text=> "Gamma",
				      -width=> $t1_mod_size,
				      -background=> $color_printA,
				      -value=> "gamma",
				      -command=> \&gam_cb,
				      -variable=> \$t1_dist_var
    )->pack(-anchor=> "w");
$t1_dist[3] = $t1_left4t->Radiobutton(-text=> "Exponential",
				      -width=> $t1_mod_size,
				      -background=> $color_printA,
				      -value=> "exp",
				      -command=> \&ex_cb,
				      -variable=> \$t1_dist_var
    )->pack(-anchor=> "w");
if ($cgig) {
	$t1_dist[4] = $t1_left4t->Radiobutton(-text=> "GIG",
					      -width=> $t1_mod_size,
					      -background=> $color_printA,
					      -value=> "gig",
					      -command=> \&gig_cb,
					      -variable=> \$t1_dist_var
	    )->pack(-anchor=> "w");
}



#}}}

my $t1_left3t = $t1_top->Frame(-background=> $color_back#{{{
    )->pack(-side=> "left",
	    -anchor=> "n",
	    -pady=> 2,
	    -padx=> 5);

my $t1_size_eqd = 8;

my $t1_left3t1 = $t1_left3t->Frame(-background=> $color_back,#{{{
				   -width=> $t1_size_eqd
    )->pack(-side=> "top",
	    -pady=> 2,
	    -padx=> 5);

my $t1_dist_p1 = $t1_left3t1 ->Label( -justify=>"left",
				      -width=> $t1_size_eqd + 2,
				      -text=> "Distribution\nParameters:",
				      -relief=>"flat", 
				      -background => $color_back
    )->pack(-anchor=>"nw");

#}}}

my $t1_left3t2 = $t1_left3t->Frame(-background=> $color_back,#{{{
				   -width=> $t1_size_eqd
    )->pack(-side=> "top",
	    -pady=> 2,
	    -padx=> 5);

my $t1_dist_p1 = $t1_left3t2 ->Label( -justify=>"left",
				      -width=> $t1_size_eqd,
				      -text=> "",
				      -relief=>"flat", 
				      -background => $color_back
    )->pack(-anchor=>"nw");

my $t1_p_dist_p1 = $t1_left3t2 ->Entry(-borderwidth=>1,
				       -background=> $color_back,
				       -justify=> "left", 
				       -relief=> "sunken", 
				       -textvariable=> \$t1_dist_par1,
				       -state=> "disabled",
				       -width=> 5,
    ) ->pack(-side=>"left",
	     -anchor=>"nw");

#}}}

my $t1_left3t3 = $t1_left3t->Frame(-background=> $color_back,#{{{
				   -width=> $t1_size_eqd
    )->pack(-side=> "top",
	    -pady=> 2,
	    -padx=> 5);

my $t1_dist_p2 = $t1_left3t3 ->Label( -justify=>"left",
				      -width=> $t1_size_eqd,
				      -text=> "",
				      -relief=>"flat", 
				      -background => $color_back
    )->pack(-anchor=>"nw");

my $t1_p_dist_p2 = $t1_left3t3 ->Entry(-borderwidth=>1,
				       -background=> $color_back,
				       -justify=> "left", 
				       -relief=> "sunken", 
				       -textvariable=> \$t1_dist_par2,
				       -state=> "disabled",
				       -width=> 5,
    ) ->pack(-side=>"left",
	     -anchor=>"nw");
#}}}

my $t1_left3t4 = $t1_left3t->Frame(-background=> $color_back,#{{{
				   -width=> $t1_size_eqd);

my $t1_dist_p3 = $t1_left3t4 ->Label( -justify=>"left",
				      -width=> $t1_size_eqd,
				      -text=> "Psi",
				      -relief=>"flat", 
				      -background => $color_back
    )->pack(-anchor=>"nw");

my $t1_p_dist_p3 = $t1_left3t4 ->Entry(-borderwidth=>1,
				       -background=> $color_back,
				       -justify=> "left", 
				       -relief=> "sunken", 
				       -textvariable=> \$t1_dist_par3,
				       -width=> 5,
    ) ->pack(-side=>"left",
	     -anchor=>"nw");
#}}}

#}}}

my $t1_right = $t1_top->Frame(-background=> $color_back#{{{
    )->pack(-side=> "right",
	    -anchor=> "n",
	    -pady=> 2,
	    -padx=> 5);

my @t1_gen;

my $t1_gen_lab = $t1_right->Label(-text=> "Generate:",
				  -background=> $color_back,
    )->pack(-anchor=> "w",
	    -pady=> 5);
$t1_gen[0] = $t1_right->Checkbutton(-text=> "Tags",
				    -background=> $color_back,
				    -highlightthickness=> 0,
				    -variable=> \$t1_gen_tag
    )->pack(-anchor=> "w");
$t1_gen[1] = $t1_right->Checkbutton(-text=> "Distribution",
				    -background=> $color_back,
				    -highlightthickness=> 0,
				    -variable=> \$t1_gen_dist
    )->pack(-anchor=> "w");
$t1_gen[2] = $t1_right->Checkbutton(-text=> "Count",
				    -background=> $color_back,
				    -highlightthickness=> 0,
				    -variable=> \$t1_gen_count
    )->pack(-anchor=> "w");

my $t1_sub_button = $t1_right->Button(-text=> "modify",
				      -command=> sub {&t1_mod_window;},
				      -width=> 10
    )->pack(-side=> "bottom",
	    -pady=> 5);

my $t1_sub_button = $t1_right->Button(-text=> "Generate",
				      -command=> \&t1_generate,
				      -width=> 10
    )->pack(-side=> "bottom",
	    -pady=> 5);

#}}}

# radio button functions #{{{

sub uni_cb {
	$t1_dist_par1 = "-";
	$t1_dist_par2 = "-";
	$t1_dist_p1->configure(
	-text=> "");
	$t1_dist_p2->configure(
		-text=> "");
	$t1_p_dist_p1->configure(
		-state=> "disabled");
	$t1_p_dist_p2->configure(
		-state=> "disabled");
	$t1_left3t4 ->pack("forget"); 
}

sub nor_cb {
	$t1_dist_par1 = 0;
	$t1_dist_par2 = 10;
	$t1_dist_p1->configure(
		-text=> "Mean");
	$t1_dist_p2->configure(
		-text=> "Variance");
	$t1_p_dist_p1->configure(
		-state=> "normal");
	$t1_p_dist_p2->configure(
		-state=> "normal");
	$t1_left3t4 ->pack("forget"); 
}

sub gam_cb {
	$t1_dist_par1 = 1;
	$t1_dist_par2 = 1;
	$t1_dist_p1->configure(
		-text=> "Theta");
	$t1_dist_p2->configure(
		-text=> "Alpha");
	$t1_p_dist_p1->configure(
		-state=> "normal");
	$t1_p_dist_p2->configure(
		-state=> "normal");
	$t1_left3t4 ->pack("forget"); 
}

sub ex_cb {
	$t1_dist_par1 = 1;
	$t1_dist_par2 = "-";
	$t1_dist_p1->configure(
		-text=> "Lambda");
	$t1_dist_p2->configure(
		-text=> "");
	$t1_p_dist_p1->configure(
		-state=> "normal");
	$t1_p_dist_p2->configure(
		-state=> "disable");
	$t1_left3t4 ->pack("forget"); 
}

sub gig_cb {
	$t1_dist_par1 = -0.6;
	$t1_dist_par2 = 0.05;
	$t1_dist_par3 = 0.003;
	$t1_dist_p1->configure(
		-text=> "Lambda");
	$t1_dist_p2->configure(
		-text=> "Chi");
	$t1_p_dist_p1->configure(
		-state=> "normal");
	$t1_p_dist_p2->configure(
		-state=> "normal");
	$t1_left3t4 ->pack(-side=> "top",
		-pady=> 2,
		-padx=> 5);
}



#}}}

#}}}

my $t1_bottom1 = $tab1->Frame( -background=> $color_back,#{{{
)->pack(-side=> "bottom", 
	-padx=> 10,
	-pady=> 10,
	-fill=> "x");


#}}}

my $t1_bottom2 = $tab1->Frame( -background=> $color_back,#{{{
)->pack(-side=> "bottom", 
	-fill=> "both",
	-padx=> 10,
	-pady=> 0,
	-expand=> "y");


my $t1_book = $t1_bottom2->NoteBook(-inactivebackground=> $color_menu_bar, #{{{
	-relief=> "flat",
	-background=> $color_printA,
	-backpagecolor=> $color_back
)->pack(-fill=> "both",
	-expand=> "both",
	-side=> "left",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

my $t1_tab1 = $t1_book->add("t1_Tab1",  #{{{
	-label=> "Count");

$t1_tab1->configure(-background=> $color_printA);

my $t1_printArea1 = $t1_tab1 ->Scrolled( "Text", 
	-background=> $color_printA,
	-borderwidth=> 1, 
	-width=> 30,
	-relief=> "flat", 
	-scrollbars=> "se", 
	-wrap=> "none"
)->pack(-fill=> "both",
	-expand=> "both",
	-side=> "right",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

$t1_printArea1->configure(-font => "pfont");

#}}}

my $t1_tab2 = $t1_book->add("t1_Tab2", #{{{
	-label=> "Expression");

$t1_tab2->configure(-background=> $color_printA);

my $t1_printArea2 = $t1_tab2 ->Scrolled( "Text", 
	-background=> $color_printA,
	-borderwidth=> 1, 
	-width=> 30,
	-relief=> "flat", 
	-scrollbars=> "se", 
	-wrap=> "none"
)->pack(-fill=> "both",
	-expand=> "both",
	-side=> "right",
	-padx=> 5,
	-pady=> 5,
	-anchor=> "w");

$t1_printArea2->configure(-font => "pfont");

#}}}

#}}}

#}}}

sub t1_generate { #{{{
	if ($t1_gen_tag) {
		&t1_generate_t();
			$t1_book->raise("t1_Tab2");
	}
	if ($t1_gen_dist) {
		&t1_generate_e();
		$t1_book->raise("t1_Tab2");
	}
	if ($t1_gen_count) {
		&t1_generate_c();
		$t1_book->raise("t1_Tab1");
	}
}

#}}}

sub t1_generate_t { #{{{
	$main->configure(-cursor=>"watch");
	$main->update();

	my $print = $t1_printArea2->get("0.0", "end - 1 chars");

	my @list = split(/\n/, $print);
	my @counts =();
	
	foreach my $line(@list) {
		$line = &clean($line);
		if (!$line) {
			next;
		}

		(my $tag, my $count) = split(/=/, $line);
		push(@counts, $count);
	}

	my $n = @counts;

	my @tags =();

	if ($n != $t1_par2) {
		@tags = &tag_generator($t1_par1, $t1_par2);
	}
	else {
		@tags = &tag_generator($t1_par1, $n);
	}

	$t1_printArea2->delete("1.0", "end");

	if (@tags == 0) {
		$main->configure(-cursor=>"arrow");
		return;
	}
	
	my $nn = @tags;
	my $k = 1 / $nn;
	
	if ($n != $t1_par2) {
		for(my $i = 0; $i < $nn; $i++) {
			$t1_printArea2->insert("end", "$tags[$i]=$k\n");
		}
	}
	else {
		for(my $i = 0; $i < $n; $i++) {
			$t1_printArea2->insert("end", "$tags[$i]=$counts[$i]\n");
		}
	}

	$main->configure(-cursor=>"arrow");
}

#}}}

sub t1_generate_e { #{{{
	$main->configure(-cursor=>"watch");
	$main->update();

	my $print = $t1_printArea2->get("0.0", "end - 1 chars");

	my @list = split(/\n/, $print);

	my @tags =();

	foreach my $line(@list) {
		$line = &clean($line);
		if (!$line) {
			next;
		}

		(my $tag, my $p) = split(/=/, $line);
		push(@tags, $tag);
	}

	my $n = @tags;

	my @count = &dist_generator($n, $t1_dist_var, $t1_dist_par1, $t1_dist_par2, $t1_dist_par3);

	$t1_printArea2->delete("1.0", "end");

	if (@count == 0) {
		$main->configure(-cursor=>"arrow");
		return;
	}

	for(my $i = 0; $i < $n; $i++) {
		$t1_printArea2->insert("end", "$tags[$i]=$count[$i]\n");
	}
	$main->configure(-cursor=>"arrow");
}

#}}}

sub t1_generate_c { #{{{
	$main->configure(-cursor=>"watch");
	$main->update();

	my $print = $t1_printArea2->get("0.0", "end - 1 chars");

	my @list = split(/\n/, $print);

	my @tags =();
	my @ps =();

	foreach my $line(@list) {
		$line = &clean($line);
		if (!$line) {
			next;
		}

		(my $tag, my $p) = split(/=/, $line);
		push(@tags, $tag);
		push(@ps, $p);
	}

	my @count = &count_generator(\@ps, $t1_total);

	$t1_printArea1->delete("1.0", "end");
	$t2_printArea1->delete("1.0", "end");
	$t2_printArea2->delete("1.0", "end");
	$t3_printArea1->delete("1.0", "end");
	$t3_printArea2->delete("1.0", "end");
	$t3_printArea3->delete("1.0", "end");

	if (@count == 0) {
		$main->configure(-cursor=>"arrow");
		return;
	}
	
	my $n = int(@tags);

	for(my $i = 0; $i < $n; $i++)  {
		if ($count[$i] < 1) {
			next;
		}
		$t1_printArea1->insert("end", "$tags[$i]=$count[$i]\n");
		$t2_printArea1->insert("end", "$tags[$i]=$count[$i]\n");
		$t3_printArea1->insert("end", "$tags[$i]=$count[$i]\n");
	}
	$main->configure(-cursor=>"arrow");
}

#}}}

sub t1_modify { #{{{
	$main->configure(-cursor=>"watch");
	$main->update();

	my $print = $t1_printArea2->get("0.0", "end - 1 chars");

	my @list = split(/\n/, $print);

	my @tags =();
	my @ps =();

	foreach my $line(@list) {
		$line = &clean($line);
		if (!$line) {
			next;
		}

		(my $tag, my $p) = split(/=/, $line);
		push(@tags, $tag);
		push(@ps, $p);
	}

	$t1_printArea2->delete("1.0", "end");

	my $n = int(@tags);

	if ($n == 0 || @ps == 0) {
		$main->configure(-cursor=>"arrow");
		return;
	}

	my $total = 0;

	for(my $i = 0; $i < $n; $i++) {
		my $e = rand();
		if ($e > $t1_mod_n / $n) {
			$total += $ps[$i];
			next;
		}
		my $r = 0;
		while($r <= 0) {
			$r = &normal * $t1_mod_d + $t1_mod_s;
		}
		my $mm = rand(2);
		if ($mm > 1) {
			$ps[$i] = $ps[$i] * $r;
		}
		else {
			$ps[$i] = $ps[$i] / $r;
		}
		$total += $ps[$i];
	}

	for(my $i = 0; $i < $n; $i++)  {
		$t1_printArea2->insert("end", "$tags[$i]=".$ps[$i]/$total."\n");
	}
	$main->configure(-cursor=>"arrow");

}

#}}}

sub t1_save_c { #{{{
	my $print = $t1_printArea1->get("0.0", "end - 1 chars");
	$print = &clean($print);

	if (!$print) {
		print "Warning :: No tags count to save\n";
		return;
	}

	my $ret = $main->getSaveFile(-filetypes => [["Text File", ".txt"], ["Tag Count", ".ct"], ["All", "*"]],
		-initialfile      => $t1_save_file,
		-title            => "Save Tag Counts",
	);

	if (!$ret) {
		return;
	}
	
	$t1_save_file = $ret;
	
	open OUT, ">$t1_save_file" or die "Could not open $t1_save_file: $!\n";

	print STDERR "Saving counts to file [$t1_save_file]...\n";
	print OUT $print;

	close OUT;
}

#}}}

sub t1_save_e { #{{{
	my $print = $t1_printArea2->get("0.0", "end - 1 chars");
	$print = &clean($print);

	if (!$print) {
		print "Warning :: No tags expression to save\n";
		return;
	}

	my $ret = $main->getSaveFile(-filetypes => [["Text File", ".txt"], ["Tag Count", ".ct"], ["All", "*"]],
		-initialfile      => $t1_save_file,
		-title            => "Save Tag Counts",
	);

	if (!$ret) {
		return;
	}
	
	$t1_save_file = $ret;
	
	open OUT, ">$t1_save_file" or die "Could not open $t1_save_file: $!\n";

	print STDERR "Saving expressions to file [$t1_save_file]...\n";
	print OUT $print;

	close OUT;
}

#}}}
sub import_tags_and_counts { #{{{
	if (!open(IN, "<$t1_import")) {
		print "Could not open $t1_import, $!\n";
		return;
	}	
	#
	#clean print area
	#
	$t1_printArea2->delete("1.0", "end");

	my $n = 0;
	my $sum = 0;
	my @counts =();
	my @tags =();
	while(my $in = <IN>) {
		(my $tag, my $count) = split(/=/, $in);
		$tag = &clean($tag);
		$count = &clean($count);
		#
		#if incomplete data, skip accounting
		#
		if (!$tag || !$count) {
			next;
		}
		push(@counts, $count);
		push(@tags, $tag);
		$n++;
		$sum += $count;
	}
	#
	#if invalid sum, show just the tags
	#
	if ($sum < 0){
	    #
	    #this should NOT happen
	    #
	    print "Error, negative count\n";
	    close IN;
	    return;
	}
	#
	#no counts were given
	#
	if ($sum == 0) {
		for(my $i = 0; $i < $n; $i++) {
			$t1_printArea2->insert("end", $tags[$i]."\n");
		}
	}

	else {
		for(my $i = 0; $i < $n; $i++) {
			$t1_printArea2->insert("end", $tags[$i]."=".($counts[$i]/$sum)."\n");
		}
	}

	$t1_book->raise("t1_Tab2");

	close IN;
}

#}}}

sub import_only_counts { #{{{

    if (!open(IN, "<$t1_import")) {
	print "Could not open $t1_import, $!\n";
	return;
    }	
    
    $t1_printArea2->delete("1.0", "end");
    
    my $entries = 0;
    my $sum = 0;
    my @counts =();
    while(my $in = <IN>) {
	my $count = &clean($in);
	#
	#in case we have an empty line, or zero
	#
	if (!$count) {
	    next;
	}
	push(@counts, $count);
	
	$sum += $count;
    }
    
    $entries = @counts;
    
    if (!$entries) {
	return;
    }
    
    for(my $i = 0; $i < $entries; $i++) {
	#
	#we normalize counts to sum 1
	#
	$t1_printArea2->insert("end", "=".($counts[$i]/$sum)."\n");
    }
    
    $t1_par2 = $entries;
    
    $t1_book->raise("t1_Tab2");
    
    close IN;
}

#}}}

sub t1_load_pop { #{{{
    my $ret = $main->getOpenFile(-filetypes => [["Text File", ".txt"], 
						["Ditag list", ".dt"], 
						["All", "*"]],
				 -initialfile      => $t1_import,
				 -title            => "Import Count Expression"
	);

    if ($ret) {
	$t1_import = $ret;
	&import_tags_and_counts();
    }
}

#}}}

sub t1_load_pop_2 { #{{{

    my $ret = $main->getOpenFile(-filetypes => [["Text File", ".txt"], 
						["All", "*"]],
				 -initialfile      => $t1_import_2,
				 -title            => "Import Expression"
	);
    
    if ($ret) {
	$t1_import = $ret;
	&import_only_counts();
    }
}

#}}}

#}}}

#
#END OF FIRST TAB (Tag Count Generator)
#


#
#BEGINNING OF SECOND TAB (Trim Tags)
#
# trim_tags #{{{

my $t2_prob = 0;
my $t2_cutSize = 18;
my $t2_fix = 0;
my $t2_ssize = 1;
my $t2_save_file = "count_trim.txt";
my $t2_p = 0;

my $t2_top = $tab2->Frame( -background=> $color_back #{{{
    )->pack(-side=> "top",
	    -fill => "both",
	    -padx=> 5,
	    -pady=> 5);

my $t2_left1t = $t2_top->Frame(-background=> $color_back,#{{{
			       -width=> 150
    )->pack(-side=> "left",
	    -pady=> 2,
	    -padx=> 5);

my $t2_size_eq = 25;

my $t2_left1t1 = $t2_left1t->Frame(-background=> $color_back,#{{{
				   -width=> $t2_size_eq
    )->pack(-side=> "top",
	    -anchor=> "e",
	    -pady=> 2,
	    -padx=> 5);

my $t2_opt1 = $t2_left1t1->Radiobutton(-width=> $t1_mod_size,
				       -background=> $color_back,
				       -value=> 0,
				       -width=> 0,
				       -border=> 1,
				       -variable=> \$t2_fix,
    )->pack(-side=> "left",
	    -anchor=> "w");

my $t2_seq_size = $t2_left1t1 ->Label( -justify=>"left",
				       -text=>"Enzyme cutting rate(0-100%)",
				       -relief=>"flat", 
				       -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"e");

my $t2_p_seq_size = $t2_left1t1 ->Entry(-borderwidth=>1,
					-background=> $color_back,
					-justify=> "left", 
					-relief=> "sunken", 
					-textvariable=> \$t2_prob,
					-width=> 5,
					-state=> "normal" 
    ) ->pack(-side=>"left",
	     -anchor=>"e");

my $t2_seq_size_p = $t2_left1t1 ->Label( -justify=>"left",
					 -text=>"%",
					 -relief=>"flat", 
					 -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"e");

my $t2_seq_size2 = $t2_left1t1 ->Label( -justify=>"left",
					-text=>"to cut the last ",
					-relief=>"flat", 
					-background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"e");

my $t2_n_seq_size = $t2_left1t1 ->Entry(-borderwidth=>1,
					-background=> $color_back,
					-justify=> "left", 
					-relief=> "sunken", 
					-textvariable=> \$t2_ssize,
					-width=> 5,
					-state=> "normal" 
    ) ->pack(-side=>"left",
	     -anchor=>"e");

my $t2_seq_size_n = $t2_left1t1 ->Label( -justify=>"left",
					 -text=>" base(s)",
					 -relief=>"flat", 
					 -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"e");


#}}}

my $t2_left1t2 = $t2_left1t->Frame(-background=> $color_back#{{{
    )->pack(-side=> "bottom",
	    -anchor=>"w",
	    -pady=> 2,
	    -padx=> 5);

my $t2_opt2 = $t2_left1t2->Radiobutton(-width=> $t1_mod_size,
				       -background=> $color_back,
				       -value=> 1,
				       -width=> 0,
				       -border=> 1,
				       -variable=> \$t2_fix,
    )->pack(-side=> "left",
	    -anchor=> "w");

my $t2_seq_num = $t2_left1t2 ->Label( -justify=>"left",
				      -text=>"Trim all tags to:",
				      -relief=>"flat", 
				      -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

my $t2_p_seq_num = $t2_left1t2 ->Entry(-borderwidth=>1,
				       -background=> $color_back,
				       -justify=> "left", 
				       -relief=> "sunken", 
				       -textvariable=> \$t2_cutSize,
				       -width=> 5,
				       -state=> "normal" 
    ) ->pack(-side=>"left",
	     -anchor=>"w");

my $t2_seq_num_p = $t2_left1t2 ->Label( -justify=>"left",
					-text=>"bp",
					-relief=>"flat", 
					-background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

#}}}

#}}}

#}}}

my $t2_bottom1 = $tab2->Frame( -background=> $color_back,#{{{
    )->pack(-side=> "bottom", 
	    -padx=> 10,
	    -pady=> 10,
	    -fill => "x");

my $t2_p_bar_s = 200;

my $t2_p_bar = $t2_bottom1->ProgressBar(-width => 20,
					-length => $t2_p_bar_s,
					-anchor => 'w',
					-from => 0,
					-to => $t2_p_bar_s,
					-blocks => 20,
					-colors => [0, 'green', 100, 'yellow' , 180, 'red'],
					-variable => \$t2_p
    )->pack(-side=> "bottom",
	    -expand=> "x",
	    -fill=> "x",
	    -anchor=> "e");

#}}}

my $t2_bottom2 = $tab2->Frame(-background=> $color_back#{{{
    )->pack(-side=> "bottom", 
	    -padx=> 10,
	    -pady=> 10,
	    -expand=> "both",
	    -fill => "both");

$t2_printArea1 = $t2_bottom2 ->Scrolled( "Text",  #{{{
					 -background=> $color_printA,
					 -borderwidth=> 1, 
					 -width=> 30,
					 -relief=> "sunken", 
					 -scrollbars=> "se", 
					 -wrap=> "none"
    )->pack(-fill=> "both",
	    -expand=> "both",
	    -side=> "left",
	    -padx=> 5,
	    -pady=> 5,
	    -anchor=> "e");

$t2_printArea1->configure(-font => "pfont");

#}}}

my $t2_trim_button = $t2_bottom2->Button(-text=> "=>\nTrim",
					 -command=> \&trim,
					 -width=> 5
    )->pack(-side=> "left",
	    -anchor=> "e");

$t2_printArea2 = $t2_bottom2 ->Scrolled( "Text", #{{{
					 -background=> $color_printA,
					 -borderwidth=> 1, 
					 -width=> 30,
					 -relief=> "sunken", 
					 -scrollbars=> "se", 
					 -wrap=> "none"
    )->pack(-fill=> "both",
	    -expand=> "both",
	    -side=> "right",
	    -padx=> 5,
	    -pady=> 5,
	    -anchor=> "w");


$t2_printArea2->configure(-font => "pfont");

#}}}

#}}}

sub trim { #{{{
    #
    #warns that we are working, changing cursor image
    #
    $main->configure(-cursor=>"watch");
    $main->update();
    
    $t2_p = 0;
    #
    #clean appropriate display area
    #
    my $in = $t2_printArea1->get("1.0", "end");
    $t2_printArea2->delete("1.0", "end");
    $t3_printArea1->delete("1.0", "end");
    $t3_printArea2->delete("1.0", "end");
    $t3_printArea3->delete("1.0", "end");
    my $param;
    
    if (!$t2_fix) {
	$param = $t2_prob;
    }
    else {
	$param = $t2_cutSize;
    }
    
    #
    #do the job
    #
    my %ret = &trim_tags($in, $t2_fix, $param, $t2_ssize);
    
    my @keys = sort(keys(%ret));
    #
    #if no tags left
    #
    if (@keys == 0) {
	$main->configure(-cursor=>"arrow");
	return;
    }
    #
    #print trimmed tags 
    #
    foreach my $key(@keys) {
	#
	#this tab's printing area
	#
	$t2_printArea2->insert("end", "$key=$ret{$key}\n");
	#
	#next tab's printing area
	#
	$t3_printArea1->insert("end", "$key=$ret{$key}\n");
    }
    
    $t2_p = $t2_p_bar_s;
    #
    #back to old cursor
    #
    $main->configure(-cursor=>"arrow");
}

#}}}

sub t2_save { #{{{
    my $print = $t2_printArea2->get("0.0", "end - 1 chars");
    $print = &clean($print);
    
    if (!$print) {
	print "Warning :: No trimmed tags count to save\n";
	return;
    }
    
    
    my $ret = $main->getSaveFile(-filetypes => [["Text File", ".txt"], ["Tag Count", ".ct"], ["All", "*"]],
				 -initialfile      => $t2_save_file,
				 -title            => "Save Trimmed Tag Counts",
	);
    
    if (!$ret) {
	return;
    }
    
    $t2_save_file = $ret;
    
    if (!open(OUT, ">$t2_save_file")) {
	print "Could not open $t2_save_file, $!\n";
	return;
    }	
    
    print STDERR "Saving trimmed counts to file [$t2_save_file]...\n";
    print OUT $print;
    
	close OUT;
}

#}}}

#}}}
#
#END OF SECOND TAB (Trim Tags)
#

#
#BEGINNING OF THIRD TAB (Counts2Ditags
#
# counts2ditag #{{{



#
#set up tab format and visual elements
#
my $t3_save_state = 0;
my $t3_coesive_n = 2;
my $t3_rep_n = 0;
my $t3_file_s = "ditags.txt";
my $t3_file_sr = "new_count.txt";
my $t3_p = 0;
my $t4_printArea1;
my $t3_dup = 0;

my $t3_top = $tab3->Frame( -background=> $color_back #{{{
    )->pack(-side=> "top",
	    -fill => "both",
	    -padx=> 5,
	    -pady=> 5);

my $t3_left1t = $t3_top->Frame(-background=> $color_back,#{{{
			       -width=> 150
    )->pack(-side=> "left",
	    -pady=> 2,
	    -padx=> 5);

my $t3_size_eq = 25;

my $t3_left1t1 = $t3_left1t->Frame(-background=> $color_back,#{{{
				   -width=> $t3_size_eq
    )->pack(-side=> "top",
	    -anchor=> "w",
	    -pady=> 2,
	    -padx=> 5);

my $t3_seq_size = $t3_left1t1 ->Label( -justify=>"left",
				       -text=>"Cohesive end length:",
				       -relief=>"flat", 
				       -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

my $t3_p_seq_size = $t3_left1t1 ->Entry(-borderwidth=>1,
					-background=> $color_back,
					-justify=> "left", 
					-relief=> "sunken", 
					-textvariable=> \$t3_coesive_n,
					-width=> 5,
					-state=> "normal" 
    ) ->pack(-side=>"left",
	     -anchor=>"w");

my $t3_seq_size_p = $t3_left1t1 ->Label( -justify=>"left",
					 -text=>"bp",
					 -relief=>"flat", 
					 -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

#}}}

my $t3_left1t2 = $t3_left1t->Frame(-background=> $color_back#{{{
    )->pack(-side=> "top",	
	    -anchor=>"w",
	    -pady=> 2,
	    -padx=> 5);

my $t3_seq_num = $t3_left1t2 ->Label( -justify=>"left",
				      -text=>"Number of tags to create with replacement:",
				      -relief=>"flat", 
				      -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

my $t3_p_seq_num = $t3_left1t2 ->Entry(-borderwidth=>1,
				       -background=> $color_back,
				       -justify=> "left", 
				       -relief=> "sunken", 
				       -textvariable=> \$t3_rep_n,
				       -width=> 5,
				       -state=> "normal" 
    ) ->pack(-side=>"left",
	     -anchor=>"w");

my $t3_seq_num_p = $t3_left1t2 ->Label( -justify=>"left",
					-text=>"(0 for no replacement)",
					-relief=>"flat", 
					-background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

#}}}

my $t3_left1t3 = $t3_left1t->Frame(-background=> $color_back#{{{
    )->pack(-side=> "top",
	    -anchor=>"w",
	    -pady=> 2,
	    -padx=> 5);

my $t3_dup_dit = $t3_left1t3 ->Label( -justify=>"left",
				      -text=>"Artificial ditags duplication rate:",
				      -relief=>"flat", 
				      -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

my $t3_p_dup_dit = $t3_left1t3 ->Entry(-borderwidth=>1,
				       -background=> $color_back,
				       -justify=> "left", 
				       -relief=> "sunken", 
				       -textvariable=> \$t3_dup,
				       -width=> 5,
				       -state=> "normal" 
    ) ->pack(-side=>"left",
	     -anchor=>"w");

my $t3_dup_dit_p = $t3_left1t3 ->Label( -justify=>"left",
					-text=>"/100",
					-relief=>"flat", 
					-background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

#}}}

#}}}

#}}}

my $t3_bottom1 = $tab3->Frame( -background=> $color_back #{{{
    )->pack(-side=> "bottom", 
	    -padx=> 10,
	    -pady=> 10,
	-fill => "x");

my $t3_p_bar_s = 200;

my $t3_p_bar = $t3_bottom1->ProgressBar(-width => 20,
					-length => $t3_p_bar_s,
					-anchor => 'w',
					-from => 0,
					-to => $t3_p_bar_s,
					-blocks => 20,
					-colors => [0, 'green', 100, 'yellow' , 180, 'red'],
					-variable => \$t3_p
    )->pack(-side=> "bottom",
	    -expand=> "x",
	    -fill=> "x",
	    -anchor=> "e");

#}}}

my $t3_bottom2 = $tab3->Frame(-background=> $color_back#{{{
    )->pack(-side=> "bottom", 
	    -padx=> 10,
	    -pady=> 10,
	    -expand=> "both",
	    -fill => "both");

$t3_printArea1 = $t3_bottom2 ->Scrolled( "Text",  #{{{
					 -background=> $color_printA,
					 -borderwidth=> 1, 
					 -width=> 30,
					 -relief=> "sunken", 
					 -scrollbars=> "se", 
					 -wrap=> "none"
    )->pack(-fill=> "both",
	    -expand=> "both",
	    -side=> "left",
	    -padx=> 5,
	    -pady=> 5,
	    -anchor=> "e");

$t3_printArea1->configure(-font => "pfont");

#}}}

my $t3_2ditags_button = $t3_bottom2->Button(-text=> "=>\n2Ditags",
					    -command=> \&count2ditag,
					    -width=> 5
    )->pack(-side=> "left",
	    -anchor=> "e");

my $t3_book = $t3_bottom2->NoteBook(-inactivebackground=> $color_menu_bar, #{{{
				    -relief=> "flat",
				    -background=> $color_printA,
				    -backpagecolor=> $color_back
    )->pack(-fill=> "both",
	    -expand=> "both",
	    -side=> "left",
	    -padx=> 5,
	    -pady=> 5,
	    -anchor=> "w");

my $t3_tab1 = $t3_book->add("t3_Tab1",  #{{{
			    -label=> "Ditags");

$t3_tab1->configure(-background=> $color_printA);

$t3_printArea2 = $t3_tab1 ->Scrolled( "Text", 
				      -background=> $color_printA,
				      -borderwidth=> 1, 
				      -width=> 30,
				      -relief=> "flat", 
				      -scrollbars=> "se", 
				      -wrap=> "none"
    )->pack(-fill=> "both",
	    -expand=> "both",
	    -side=> "right",
	    -padx=> 5,
	    -pady=> 5,
	    -anchor=> "w");

$t3_printArea2->configure(-font => "pfont");

#}}}

my $t3_tab2 = $t3_book->add("t3_Tab2", #{{{
			    -label=> "New Count");

$t3_tab2->configure(-background=> $color_printA);

$t3_printArea3 = $t3_tab2 ->Scrolled( "Text", 
				      -background=> $color_printA,
				      -borderwidth=> 1, 
				      -width=> 30,
				      -relief=> "flat", 
				      -scrollbars=> "se", 
				      -wrap=> "none"
    )->pack(-fill=> "both",
	    -expand=> "both",
	    -side=> "right",
	    -padx=> 5,
	    -pady=> 5,
	    -anchor=> "w");

$t3_printArea3->configure(-font => "pfont");

#}}}

#}}}

#}}}

sub count2ditag { #{{{
    #
    #let the user know we are working (change cursor to a watch)
    #
    $main->configure(-cursor=>"watch");
    $main->update();
    
    #
    #initialize display area
    #
    my $in = $t3_printArea1->get("1.0", "end");
    $t3_printArea2->delete("1.0", "end");
    $t3_printArea3->delete("1.0", "end");
    $t4_printArea1->delete("1.0", "end");
    
    $t3_p = 0;
    
    #
    #now generate all ditags
    #
    my @ditag_report_lines = &counts2ditags($in, $t3_coesive_n, $t3_rep_n, $t3_dup);
    
    my $state = 0;
    
    #
    #if no ditags generated, just go back
    #
    if (@ditag_report_lines == 0) {
	$main->configure(-cursor=>"arrow");
	return;
    }
  DITAGS:
    #
    #first process ditags
    #
    while (my $one_ditag = shift(@ditag_report_lines)) {
	#
	#is this a report line or a ditag line?
	#
	if ($one_ditag eq "**") {
	    #
	    #if this is the end of the ditags....
	    #
	    last DITAGS;
	}
	#
	#display ditag in this frame and in the next
	#
	$t3_printArea2->insert("end", "$one_ditag\n");
	$t4_printArea1->insert("end", "$one_ditag\n");
    }
    #
    #now the report
    #
    foreach my $report_line (@ditag_report_lines){
	$t3_printArea3->insert("end", "$_\n");
    }
    
    $t3_p = $t3_p_bar_s;
    $main->configure(-cursor=>"arrow");
}

#}}}

sub t3_save { #{{{
    #
    #save ditags print area
    #
    my $print = $t3_printArea2->get("0.0", "end - 1 chars");
    $print = &clean($print);
    
    if (!$print) {
	print "Warning :: No ditag to save\n";
	return;
    }
    
    my $ret = $main->getSaveFile(-filetypes => [["Text File", ".txt"], ["Ditag List", ".dt"], ["All", "*"]],
				 -initialfile      => $t3_file_s,
				 -title            => "Save Ditag List",
	);
    
    if (!$ret) {
	return;
    }

    $t3_file_s = $ret;
    
    if (!open(OUT, ">$t3_file_s")) {
	print "Could not open $t3_file_s, $!\n";
	return;
    }	
    
    print STDERR "Saving ditags to file [$t3_file_s]...\n";
    print OUT $print;
    
    close OUT;
}

#}}}

sub t3_save_r { #{{{
    #
    #saves the report
    #
    my $print = $t3_printArea3->get("0.0", "end - 1 chars");
    $print = &clean($print);
    
    if (!$print) {
	print "Warning :: No new count to save\n";
	return;
    }
    
    my $ret = $main->getSaveFile(-filetypes => [["Text File", ".txt"], ["Ditag List", ".dt"], ["All", "*"]],
				 -initialfile      => $t3_file_sr,
				 -title            => "Save New Tag Count",
	);
    
    if (!$ret) {
	return;
    }
    
    $t3_file_sr = $ret;
    
    if (!open(OUT, ">$t3_file_sr")) {
	print "Could not open $t3_file_sr, $!\n";
	return;
    }	
    
    print STDERR "Saving new count to file [$t3_file_sr]...\n";
    print OUT $print;
    
    close OUT;
}

#}}}

#}}}

#
#END OF THIRD TAB (Counts 2 Ditags)
#

#
#BEGINNING OF FOURTH TAB (Ditags 2 Concatamers)
#

# ditags2concatamers #{{{

#
#prepare the tab format
#
my $t4_save_state = 0;
my $t4_min_size_n = 10;
my $t4_max_size_n = 10;
my $t4_error = 0;
my $t4_flank = 0;
my $t4_name_v = "";
my $t4_file_l = "ditags.txt";
my $t4_file_s = "concatamers.fasta";
my $t4_file_sr = "concat_report.txt";
my $t4_p = 0;


#
#put the tab' s elements, buttons, text boxes, etc
#
my $t4_top = $tab4->Frame( -background=> $color_back #{{{
    )->pack(-side=> "top",
	    -fill => "both",
	    -padx=> 5,
	    -pady=> 5);

my $t4_left1t = $t4_top->Frame(-background=> $color_back,#{{{
			       -width=> 150
    )->pack(-side=> "left",
	    -pady=> 2,
	    -padx=> 5);

my $t4_size_eq = 25;

my $t4_left1t3 = $t4_left1t->Frame(-background=> $color_back#{{{
    )->pack(-side=> "bottom",
	    -anchor=>"w",
	    -pady=> 2,
	    -padx=> 5);

my $t4_seq_num = $t4_left1t3 ->Checkbutton( -justify=>"left",
					    -text=> "Flank concatamer with random size sequence",
					    -relief=> "flat", 
					    -variable=> \$t4_flank,
					    -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

#}}}

my $t4_left1t1 = $t4_left1t->Frame(-background=> $color_back,#{{{
				   -width=> $t4_size_eq
    )->pack(-side=> "top",
	    -anchor=> "w",
	    -pady=> 2,
	    -padx=> 5);

my $t4_seq_size = $t4_left1t1 ->Label( -justify=>"left",
				       -text=>"Minimum concatamer size:",
				       -relief=>"flat", 
				       -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

my $t4_p_seq_size = $t4_left1t1 ->Entry(-borderwidth=>1,
					-background=> $color_back,
					-justify=> "left", 
					-relief=> "sunken", 
					-textvariable=> \$t4_min_size_n,
					-width=> 5,
					-state=> "normal" 
    ) ->pack(-side=>"left",
	     -anchor=>"w");

my $t4_seq_size_p = $t4_left1t1 ->Label( -justify=>"left",
					 -text=>"ditags",
					 -relief=>"flat", 
					 -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

#}}}

my $t4_left1t2 = $t4_left1t->Frame(-background=> $color_back#{{{
    )->pack(-side=> "bottom",
	    -anchor=>"w",
	    -pady=> 2,
	    -padx=> 5);

my $t4_seq_num = $t4_left1t2 ->Label( -justify=>"left",
				      -text=>"Maximum concatamer size:",
				      -relief=>"flat", 
				      -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

my $t4_p_seq_num = $t4_left1t2 ->Entry(-borderwidth=>1,
				       -background=> $color_back,
				       -justify=> "left", 
				       -relief=> "sunken", 
				       -textvariable=> \$t4_max_size_n,
				       -width=> 5,
				       -state=> "normal" 
    ) ->pack(-side=>"left",
	     -anchor=>"w");

my $t4_seq_num_p = $t4_left1t2 ->Label( -justify=>"left",
					-text=>"ditags",
					-relief=>"flat", 
					-background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

#}}}

#}}}

my $t4_left2t = $t4_top->Frame(-background=> $color_back,#{{{
			       -width=> 150
    )->pack(-side=> "left",
	    -pady=> 2,
	    -padx=> 5);

my $t4_size_eq2 = 25;

my $t4_left2t1 = $t4_left2t->Frame(-background=> $color_back,#{{{
				   -width=> $t4_size_eq2
    )->pack(-side=> "top",
	    -anchor=> "w",
	    -pady=> 2,
	    -padx=> 5);

my $t4_err = $t4_left2t1 ->Label( -justify=>"left",
				  -text=>"Punctuation error rate:",
				  -relief=>"flat", 
				  -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

my $t4_p_err = $t4_left2t1 ->Entry(-borderwidth=>1,
				   -background=> $color_back,
				   -justify=> "left", 
				   -relief=> "sunken", 
				   -textvariable=> \$t4_error,
				   -width=> 5,
				   -state=> "normal" 
    ) ->pack(-side=>"left",
	     -anchor=>"w");

my $t4_err_p = $t4_left2t1 ->Label( -justify=>"left",
				    -text=>"%",
				    -relief=>"flat", 
				    -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

#}}}

my $t4_left2t2 = $t4_left2t->Frame(-background=> $color_back#{{{
    )->pack(-side=> "bottom",
	    -anchor=>"w",
	    -pady=> 2,
	    -padx=> 5);

my $t4_name = $t4_left2t2 ->Label( -justify=>"left",
				   -text=>"Concatamers name prefix:",
				   -relief=>"flat", 
				   -background => $color_back
    )->pack(-side=> "left",
	    -anchor=>"w");

my $t4_p_name = $t4_left2t2 ->Entry(-borderwidth=>1,
				    -background=> $color_back,
				    -justify=> "left", 
				    -relief=> "sunken", 
				    -textvariable=> \$t4_name_v,
				    -width=> 20,
				    -state=> "normal" 
    ) ->pack(-side=>"left",
	     -anchor=>"w");

#}}}

#}}}

#}}}

my $t4_bottom1 = $tab4->Frame( -background=> $color_back,#{{{
    )->pack(-side=> "bottom", 
	    -padx=> 10,
	    -pady=> 10,
	    -fill => "x");

my $t4_p_bar_s = 200;

my $t4_p_bar = $t4_bottom1->ProgressBar(-width => 20,
					-length => $t4_p_bar_s,
					-anchor => 'w',
					-from => 0,
					-to => $t4_p_bar_s,
					-blocks => 20,
					-colors => [0, 'green', 100, 'yellow' , 180, 'red'],
					-variable => \$t4_p
    )->pack(-side=> "bottom",
	    -expand=> "x",
	    -fill=> "x",
	    -anchor=> "e");


#}}}

my $t4_bottom2 = $tab4->Frame(-background=> $color_back#{{{
    )->pack(-side=> "bottom", 
	    -padx=> 10,
	    -pady=> 10,
	    -expand=> "both",
	    -fill => "both");

my $t4_bottom21 = $t4_bottom2 ->Frame(-background=> $color_back#{{{
    )->pack(-side=> "left", 
	    -padx=> 10,
	    -pady=> 10,
	    -expand=> "both",
	    -fill => "both");

$t4_printArea1 = $t4_bottom21 ->Scrolled( "Text", 
					  -background=> $color_printA,
					  -borderwidth=> 1, 
					  -width=> 30,
					  -relief=> "sunken", 
					  -scrollbars=> "se", 
					  -wrap=> "none"
    )->pack(-fill=> "both",
	    -expand=> "both",
	    -side=> "left",
	    -padx=> 5,
	    -pady=> 5,
	    -anchor=> "e");

$t4_printArea1->configure(-font => "pfont");

#}}}

my $t4_bottom22 = $t4_bottom2 ->Frame(-background=> $color_back#{{{
    )->pack(-side=> "left");

my $t4_2concat_button = $t4_bottom22->Button(-text=> "=>\n2Concat",
					     -command=> \&ditag2concatamer,
					     -width=> 6
    )->pack(-side=> "left",
	    -anchor=> "e");
#}}}

my $t4_bottom23 = $t4_bottom2 ->Frame(-background=> $color_back#{{{
    )->pack(-side=> "left", 
	    -padx=> 10,
	    -pady=> 10,
	    -expand=> "both",
	    -fill => "both");

my $t4_book = $t4_bottom23->NoteBook(-inactivebackground=> $color_menu_bar, 
				     -background=> $color_printA,
				     -backpagecolor=> $color_back
    )->pack(-fill=> "both",
	    -expand=> "x");

my $t4_tab1 = $t4_book->add("t3_Tab1",  #{{{
			    -label=> "Concatamer");

$t4_tab1->configure(-background=> $color_printA);

my $t4_printArea2 = $t4_tab1 ->Scrolled( "Text", 
					 -background=> $color_printA,
					 -borderwidth=> 1, 
					 -width=> 30,
					 -relief=> "flat", 
					 -scrollbars=> "se", 
					 -wrap=> "none"
    )->pack(-fill=> "both",
	    -expand=> "both",
	    -side=> "right",
	    -padx=> 5,
	    -pady=> 5,
	    -anchor=> "w");

$t4_printArea2->configure(-font => "pfont");

#}}}

my $t4_tab2 = $t4_book->add("t3_Tab2", #{{{
			    -label=> "Report");

$t4_tab2->configure(-background=> $color_printA);

my $t4_printArea3 = $t4_tab2 ->Scrolled( "Text", 
					 -background=> $color_printA,
					 -borderwidth=> 1, 
					 -width=> 30,
					 -relief=> "flat", 
					 -scrollbars=> "se", 
					 -wrap=> "none"
    )->pack(-fill=> "both",
	    -expand=> "both",
	    -side=> "right",
	    -padx=> 5,
	    -pady=> 5,
	    -anchor=> "w");

$t4_printArea3->configure(-font => "pfont");

#}}}

#}}}

#}}}

sub ditag2concatamer { #{{{
    $main->configure(-cursor=>"watch");
    $main->update();
    
    my @ret;
    my $in = $t4_printArea1->get("1.0", "end");
    $t4_printArea2->delete("1.0", "end");
    $t4_printArea3->delete("1.0", "end");
    
    $t4_p = 0;
    
    @ret = &ditags2concatamers($in, 
			       $t4_min_size_n, 
			       $t4_max_size_n, 
			       $t4_error, 
			       $t4_flank, 
			       $t4_name_v);
    
    if (@ret == 0) {
	$main->configure(-cursor=>"arrow");
	return;
    }
    
    $t4_p = $t4_p_bar_s;
    
    my $state = 0;
    
    foreach $in(@ret) {
	if (!$state) {
	    if ($in eq "**") {
		$state = 1;
	    }
	    else {
		if ($in =~ m/>/) {
		    $t4_printArea2->insert("end", "$in\n");
		}
		else {
		    while($in) {
			my $onSize = substr($in, 0, 60);
			$t4_printArea2->insert("end", "$onSize\n");
			$in = substr($in, 60);
		    }
		}
	    }
	}
	else {
	    while($in) {
		my $onSize = substr($in, 0, 60);
		$t4_printArea3->insert("end", "$onSize\n");
		$in = substr($in, 60);
	    }
	}
    }
    $main->configure(-cursor=>"arrow");
}

#}}}

sub t4_save { #{{{
    my $print = $t4_printArea2->get("0.0", "end - 1 chars");
    $print = &clean($print);
    
    if (!$print) {
	print "Warning :: No concatamer to save\n";
	return;
    }
    
    my $ret = $main->getSaveFile(-filetypes => [["FASTA", ".fasta"], ["All", "*"]],
				 -initialfile      => $t4_file_s,
				 -title            => "Save Concatamers",
	);
    
    if (!$ret) {
	return;
    }
    
    $t4_file_s = $ret;
    
    if (!open(OUT, ">$t4_file_s")) {
	print "Could not open $t4_file_s, $!\n";
	return;
    }	
    
    
    print STDERR "Saving concatamers to file [$t4_file_s]...\n";
    print OUT $print;
    
    close OUT;
}

#}}}

sub t4_save_r { #{{{
    my $print = $t4_printArea3->get("0.0", "end - 1 chars");
    $print = &clean($print);
    
    if (!$print) {
	print "Warning :: No concatamers report to save\n";
	return;
    }
    
    my $ret = $main->getSaveFile(-filetypes => [["Text File", ".txt"], ["All", "*"]],
				 -initialfile      => $t4_file_sr,
				 -title            => "Save Concatamers Report",
	);
    
    if (!$ret) {
	return;
    }
    
    $t4_file_sr = $ret;
    
    if (!open(OUT, ">$t4_file_sr")) {
	print "Could not open $t4_file_sr, $!\n";
	return;
    }	
    
    print STDERR "Saving report to file [$t4_file_sr]...\n";
    print OUT $print;
    
    close OUT;
}

#}}}

sub load_concat { #{{{
    if (!open(IN, "<$t4_file_l")) {
	print "Could not open $t4_file_l, $!\n";
	return;
    }	
    
    $t4_printArea1->delete("1.0", "end");
    $t4_printArea2->delete("1.0", "end");
    $t4_printArea3->delete("1.0", "end");
    while(<IN>) {
	$t4_printArea1->insert("end", $_);
    }
    
    close IN;
}

#}}}

sub t4_load_pop { #{{{
    my $ret = $main->getOpenFile(-filetypes => [["Text File", ".txt"], ["Ditag list", ".dt"], ["All", "*"]],
				 -initialfile      => $t4_file_l,
				 -title            => "Load Ditag List",
	);
    
    if ($ret) {
	$t4_file_l = $ret;
	&load_concat;
    }
    
}

#}}}

#}}}
#
#END OF FOURTH TAB (Ditag 2 Concatamers)
#

MainLoop();

#
#NOW THE FUNCTIONS THAT CORRESPOND TO THE MAIN SOFTARE
#




sub save_all { #{{{
	&t1_save();
	&t2_save();
	&t3_save();
	&t3_save_r();
	&t4_save();
	&t4_save_r();
}

#}}}

sub load_count { #{{{
    #lauches a file-open window
    my $ret = $main->getOpenFile(-filetypes => [["Text File", ".txt"], 
						["Ditag list", ".dt"], ["All", "*"]],
				 -initialfile      => $count_l,
				 -title            => "Load Ditag List",
	);
    #
    #user cancelled window
    #
    if (!$ret) {
	return;
    }
    
    $count_l = $ret;
    
    if (!open(OUT, "<$ret")) {
	print "Could not open $ret, $!\n";
	return;
    }	
    
    #
    #cleans display areas
    #
    $t2_printArea1->delete("1.0", "end");
    $t2_printArea2->delete("1.0", "end");
    $t3_printArea1->delete("1.0", "end");
    $t3_printArea2->delete("1.0", "end");
    $t3_printArea3->delete("1.0", "end");
    #
    #read and display file
    #
    while(<OUT>) {
	$t2_printArea1->insert("end", $_);
	$t3_printArea1->insert("end", $_);
    }

    close OUT;
}

#}}}

sub tag_generator { #{{{
    #
    # parameter: size, number, d, p1, p2
    #
    
    my $size = shift;
    my $number = shift;
    my %generated_tags =();
    my $d = shift;
    my $max = 4**$size;
    my $n = 0;
    my @ret =();
    
    if ($size == 0) {
	return;
    }
    
    #
    #to generate unique tags, I need to collect them to verify if 
    #later tags are not the same
    #
    for(my $j = 0; $j < $number; $j++){
	my $good = 0;
	my $sequence = "";
	while(!($good)){
	    $sequence = "";
	    for(my $i = 0; $i < $size; $i++) {
		#
		#randomly choose a base
		#
		my $number  =  int(rand(4));
		my $base;
		if ($number == 0){
		    $base = "a";
		}
		elsif ($number == 1){
		    $base = "c";
		}
		elsif ($number == 2){
		    $base = "g";
		}
		else{
		    $base = "t";
		}
		#
		#increment the sequence
		#
		$sequence .= $base;
		
	    }
	    #
	    #we cannot generate a tag twice or
	    #generate a tag with a catg in it
	    #
	    if (($sequence =~ m/catg/i) || exists($generated_tags{$sequence})){
		print STDERR "trying another sequence\n";
		$good = 0;
		if ($n >= $max) {
		    $good = 1;
		}
	    }
	    else {
		$n++;
		$good = 1;
		push(@ret, $sequence);
	    }
	}
    }
    
    return @ret;
    
}

#}}}

sub dist_generator { #{{{
    #
    # parameter: size, number, d, p1, p2
    #
    
    my $number_of_unique_tags = shift;
    my %generated_tags =();
    my $distribution_type = shift;
    my $p1 = shift;
    my $p2 = shift;
    my $p3 = shift;
    ##my $total = 0;
    ##my $n = 0;
    
    if ($number_of_unique_tags == 0) {
	return;
    }
    
    my @rand =();
    (my $individualCounts, 
     my $totalCount) = &getCount($distribution_type, 
				 $p1, 
				 $p2, 
				 $p3, 
				 $number_of_unique_tags);
    if ($totalCount == 0) {
	return();
    }
    my @countsArray = @$individualCounts;
    
    my @returnArray =();
    
    foreach my $count (@countsArray) {
	push(@returnArray, $count / $totalCount);
    }
    
    return @returnArray;
    

    sub getCount {
	
	my $distribution_type = shift;
	my $p1 = shift;
	my $p2 = shift;
	my $p3 = shift;
	my $numberOfCounts = shift;
	my $totalCount = 0;
	my @countList =();
	
	if ($distribution_type eq "normal") {
	    for(my $i = 0; $i < $numberOfCounts; $i++) {
		my $oneCount = &countNormal($p1, $p2);
		push(@countList, $oneCount);
		$totalCount += $oneCount;
	    }
	}
	elsif ($distribution_type eq "gamma") {
	    for(my $i = 0; $i < $numberOfCounts; $i++) {
		my $oneCount = &countGamma($p1, $p2);
		push(@countList, $oneCount);
		$totalCount += $oneCount;
	    }
	}
	elsif ($distribution_type eq "exp") {
	    for(my $i = 0; $i < $numberOfCounts; $i++) {
		my $oneCount = &countExp($p1);
		push(@countList, $oneCount);
		$totalCount += $oneCount;
	    }
	}
	elsif ($distribution_type eq "gig") {
	    ($totalCount, my $allCounts) = &GIG($p1, $p2, $p3, $numberOfCounts);
	    @countList = @$allCounts;
	}
	else {
	    for(my $i = 0; $i < $numberOfCounts; $i++) {
		my $oneCount = rand(100000) ;
		push(@countList, $oneCount);
		$totalCount += $oneCount;
	    }
	}
	
	return(\@countList, $totalCount);
    }
    
    sub countNormal {
	my $mi = shift;
	my $ro = shift;
	my $value = 0;
	while($value <= 0) {

	    $value = &normal() * $ro + $mi;

	}
	return $value;
    }
    
    sub countGamma {
	my $k = shift;
	my $theta = shift;
	my $value = 0;
	while($value <= 0) {
	    $value = &gamma_rand($k, $theta);
	}
	
	return $value;
    }
    
    sub countExp {
	my $lambda = shift;
	
	my $value = 0;
	while($value <= 0) {
	    $value = &exponential($lambda); 
	}
	
	return $value;
    }

}

#}}}

sub count_generator { #{{{
	my $rlist = shift;
	my @plist = @$rlist;
	my $total = shift;
	my $n = int(@plist);
	my @counts;
	my @list =();
	my $sum = 0;

	foreach my $p(@plist) {
		push(@list, $sum);
		push(@counts, 0);
		$sum += $p;
	}

	for(my $i = 0; $i < $total; $i++) {
		my $k = rand();
		my $max = $n;
		my $min = 0;
		my $x = int($n / 2);
		while($max - $min > 1) {
			if ($list[$x] < $k) {
				$min = $x;
			}
			else {
				$max = $x;
			}
			$x = int(($max - $min) / 2) + $min;
		}
		$counts[$x] += 1;
	}

	return @counts;
}
#}}}

sub trim_tags { #{{{

	my $raw_data = shift;
	my $fix = shift;
	my $prob = shift;
	my $csize = shift;
	my $size;

	if ($fix) {
		$size = $prob;
	}
	else {
		$size = 0;
	}
	my %new_counts =();

	my @data = split("\n", $raw_data);

	my $total = 0;
	my %counts;

	foreach my $entry(@data) {
		chomp($entry);
		if (!$entry) {
			next;
		}
		(my $tag, my $count) = split(/=/, $entry);

		$total += $count;

		if (defined $counts{$tag}) {
			$counts{$tag} += $count;
		}
		else {
			$counts{$tag} = $count;
		}
	}

	if ($total == 0) {
		return;
	}

	my $prop = $t2_p_bar_s / $total;
	my $p = 0;

	foreach my $tag(%counts) {
		my $count = $counts{$tag};

		for(my $i = 1; $i <= $count; $i++) {
			my $new_tag;
			if ($size) {
				$new_tag = substr($tag, 0, $size);
			}
			else {
				if (rand(100) < $prob) {
					$new_tag = substr($tag, 0, -$csize);
				}
				else {
					$new_tag = $tag;
				}
			}
			if (exists($new_counts{$new_tag} )) {
				$new_counts{$new_tag} += 1;
			}
			else{
				$new_counts{$new_tag} = 1;
			}
			$p++;
			$t2_p += $prop;
			if ($p >= 1000) {
				$p = 0;
				$t2_p_bar->update();
			}
		}
	}

	return %new_counts;

}

#}}}

sub counts2ditags { #{{{

	my $in = shift;
	my $coesive = shift;
	my $total_di = shift;
	my $dup = shift;
	my @in =();
	my %tag_counts =();
	my %sort =();
	my %end2tag =();
	my %final_count =();
	my @final_tags =();
	my @tags =();
	my $total_count = 0; 
	my $cut_size = 1;
	my @all_tags =();
	my @return;

	my $dup = $dup / 100;

	#
	#get the tag counts and tags
	#

	my $total = 0;

	@in = split(/\n/, $in);

	while(my $entry = shift @in){
		chomp($entry); 
		(my $tag,my $count) = split("=", $entry);
		$tag_counts{$tag} = $count;
		$total += $count;
	}

	foreach my $tag(keys(%tag_counts)) {
		while($tag_counts{$tag}) {
			$tag_counts{$tag}--;
			push(@all_tags,rand()."=>".$tag);
		}
	}

	if (@all_tags == 0) {
		return;
	}

	#
	#sort the ditags by the given random number
	#

	my @sorted = sort(@all_tags);


	foreach my $entry(@sorted) {
		my($junk, $tag) = split("=>", $entry);
		push(@final_tags, $tag);
	}

	my $prop;

	if ($total_di) {
		$prop = $t3_p_bar_s / $total_di;
	}
	else { 
		$prop = $t3_p_bar_s / @final_tags * 2;
	}

	my $togo = $total_di;
	my $up = 0;
	if ($coesive) {
		while(@final_tags) {
			my $tag;

			if ($total_di) {
				my $tg = int(rand($total));
				$tag = $final_tags[$tg];
			}
			else {
				$tag = shift(@final_tags);
			}

			my $last2 = substr($tag, -$coesive);
			my $last2reverse = &reverseComplement($last2);
			if (my $tag2 = shift(@{$end2tag{$last2reverse}})){
				my $ditag = $tag2 . substr(&reverseComplement($tag), $coesive);
				my $n = &poisson($dup);
				for(my $i = 0; $i < $n + 1; $i++) {
					push(@return, $ditag);
				}
				if (defined $final_count {$tag}) {
					$final_count {$tag}++;
				}
				else {
					$final_count {$tag} = 1;
				}
				if (defined $final_count {$tag2}) {
					$final_count {$tag2}++;
				}
				else {
					$final_count {$tag2} = 1;
				}
				if ($total_di) {
					$togo--;
					if ($togo <= 0) {
						@final_tags =();
					}
				}
				$t3_p += $prop;
				$up++;
				if ($up > 1000) {
					$t3_p_bar->update();
					$up = 0;
				}

			}
			else {
				push(@{$end2tag{$last2}},$tag);
			}
		}
	}


	else {
		while(@final_tags) {
			my $first;
			if ($total_di) {
				my $tg = int(rand($total));
				$first = $final_tags[$tg];
			}
			else {
				$first = shift(@final_tags);
			}
			my $second;
			if ($total_di) {
				my $tg = int(rand($total));
				$second = $final_tags[$tg];
			}
			else {
				$second = shift(@final_tags);
			}


			if ($second){
				my $ditag = $first . &reverseComplement($second);
				my $n = &poisson($dup);
				for(my $i = 0; $i < $n + 1; $i++) {
					push(@return, $ditag);
				}
				if (defined $final_count {$first}) {
					$final_count {$first}++;
				}
				else {
					$final_count {$first} = 1;
				}
				if (defined $final_count {$second}) {
					$final_count {$second}++;
				}
				else {
					$final_count {$second} = 1;
				}

			}
			if ($total_di) {
				$togo--;
				if ($togo <= 0) {
					@final_tags =();
				}
			}
			$t3_p += $prop;
			$up++;
			if ($up >= 1000) {
				$t3_p_bar->update();
				$up = 0;
			}


		}
	}

	push(@return, "**");

	foreach my $tag(sort(keys(%final_count))) {
		push(@return, "$tag=$final_count{$tag}");
	}

	return @return;

	#
	#return a  tag from the bin, randomly or not, as setted
	#
	sub getTag {
		if ($total_di) {
			my $tag = int(rand($total));
			return $final_tags[$tag];
		}
		else {
			return shift(@final_tags);
		}
	}

	#
	#return the reverse complement of the DNA sequence
	#
	sub reverseComplement {
		my $string = shift();
		my $base;
		my @split;
		@split = split(//, $string);
		$string = "";
		while(@split) {
			$base = pop(@split);
			if ($base eq "a") {
				$string .= "t";
			}
			elsif ($base eq "t") {
				$string .= "a";
			}
			elsif ($base eq "c") {
				$string .= "g";
			}
			else {
				$string .= "c";
			}
		}

		return $string;
	}

}

#}}}

sub ditags2concatamers { #{{{

    my $in = shift;
    my $smin = shift;
    my $smax = shift;
    my $separator_error_rate = shift;
    my $cut = shift;
    my $prefix = shift;
    my $punc = "catg";
    my @split =();
    my @concat =();
    my $randf = 1;
    my $concatamer = "";
    my $separator = "";
    my $base;
    my $arg;
    my $bad_separators = 0;
    my @list =();
    my $n;
    my @return =();
    my @errors;
    
    $randf = $smax - $smin + 1;
    
    $n = $smin + int(rand($randf));
    
    my @in = split(/\n/, $in);
    
    my $pre = "";
    my $pos = "";
    my $conc_n = 0;
    my $done = 0;
    
    if (@in == 0) {
	return
    }
    
    my $prop = $t4_p_bar_s / @in;
    my $p = 0;
    while(my $ditag = shift(@in)) {
	chomp($ditag);
	$ditag = &clean($ditag);
	if (!$ditag) {
	    next;
	}
	$separator = &new_separator($separator_error_rate);
	if ($separator ne $punc) {
	    push(@errors, "*$separator$ditag");
			$bad_separators++;
	}
	$t4_p += $prop;
	
	if ($done == $n) {
	    push(@return, ">$prefix$conc_n");
	    push(@return, "$concatamer$separator$pos");
	    push(@return, " ");
	    $concatamer = "";
	    $n = $smin + int(rand($randf));
	    $done = 0;
	    #$t4_p_bar->update();
	}
	if ($done == 0) {
	    $conc_n++;
	    if ($cut) {
		my $cutpoint = int(rand(length($ditag) + 1));
		$pos = substr($ditag, 0, $cutpoint);
		$pre = substr($ditag, $cutpoint);
		$concatamer .= $pre;
	    }
	    else {
		$concatamer .= $separator . $ditag;
	    }
	    $done++;
	}
	else {
	    $concatamer .= $separator . $ditag;
	    $done++;
	}
    }
    
    if ($concatamer) {
	push(@return, ">$prefix$conc_n");
	push(@return, "$concatamer$separator$pos");
    }
    
    push(@return, "**");
    
    foreach my $err(@errors) {
	push(@return, $err);
    }
    
    push(@return, "BAD SEPARATORS : $bad_separators \n");
    
    return @return;
    
    sub new_separator {
	my $error_rate = shift;
	my $base;
	my @index2base =("a", "c", "t", "g");
	my $position;
	
	if (rand(100) < $error_rate) {
	    $position = int(rand(4));
	    if ($position == 0){
		while(($base = $index2base[int(rand(4))]) eq "c") {};
		$separator = $base."atg";
	    }
	    elsif ($position == 1){
		while(($base = $index2base[int(rand(4))]) eq "a") {};
		$separator = "c".$base."tg";
	    }
	    elsif ($position == 2){
		while(($base = $index2base[int(rand(4))]) eq "t") {};
		$separator = "ca".$base."g";
	    }
	    else{
		while(($base = $index2base[int(rand(4))]) eq "g") {};
		$separator = "cat".$base;
	    }
	    
	}
	else {
	    $separator = "catg";
	}
	
	$separator;
    }
    
    
}

#}}}

sub gamma_rand { #{{{
	my $k = shift;
	my $theta = shift;
	my $sum = 0;
	my $ret;
	my $intk = int($k);
	my $E = 0;

	for(my $i = 0; $i < $k; $i++) {
		$sum += log(rand());
	}

	$E = &gamma_func($k - $intk);
	$ret = $theta *($E - $sum);

	return $ret;
} 

#}}}

sub gamma_func { #{{{
	my $m = 0;
	my @v;
	my @E;
	my @n;
	my $e = 2.71828183;
	my $delta = shift;
	if (!$delta) {
		return 0;
	}
	$v[0] = $e /($e + $delta);
	do {
		$m++;
		$v[2 * $m - 1] = rand();
		$v[2 * $m] = rand();
		if ($v[2 * $m - 2] <= $v[0]) {
			$E[$m] = $v[2 * $m - 1]**(1 / $delta);
			$n[$m] = $v[2 * $m] * $E[$m]**($delta - 1);
		}
		else {
			$E[$m] = 1 - log($v[2 * $m - 1]);
			$n[$m] = $v[2 * $m] * $e**(-$E[$m]);
		}
	} while($n[$m] >($E[$m]**($delta - 1) * $e**(-$E[$m])));

	return $E[$m];
}

#}}}

sub poisson { #{{{
	my $lambda = shift;
	my $k = 0; 
	my $p = 1; 
	my $e = 2.71828183;
	my $L = $e**(-$lambda);

	while($p >= $L) {
		$k++; 
		$p = $p * rand();
	}   

	return $k - 1;
}

#}}}

sub exponential { #{{{
	my $lambda = shift;

	my $r = rand();

	my $e = -log($r) / $lambda;

	return $e
}

#}}}

sub GIG { #{{{
	my $p1 = shift;
	my $p2 = shift;
	my $p3 = shift;
	my $n = shift;

	print("Rscript gig.R $n $p1 $p2 $p3 > gig.gen\n");
	system("Rscript gig.R $n $p1 $p2 $p3 > gig.gen");

	if (!open(IN, "<gig.gen")) {
		print STDERR "File [gig.gen] not found, Generation failed...\n";
		return 0;
	}

	my @ret =();
	my $total = 0;

	while(my $in = <IN>) {
		chomp($in);
		my @gen = split(/ /, $in);
		$total += $gen[1];
		push(@ret, $gen[1]);
	}

	return($total, \@ret);
}

#}}}

sub normal { #{{{
	my $v1;
	my $v2;
	my $r;

	$r = 1;
	while($r >= 1) {
		$v1 = 2 * rand() - 1;
		$v2 = 2 * rand() - 1;
		$r = $v1**2 + $v2**2;
	}
	$r = sqrt(-2 * log($r) / $r);

	return $v2 * $r;
}

#}}}

sub clean { #{{{
	my $string = shift;

	if ($string) {
		$string =~ s/^\s+//;
		$string =~ s/\s+$//;
	}

	return $string;
}

#}}}

sub checkGIG { #{{{
	if (!-e "gig.R") {
		print STDERR "gig.R could not be found\n";
		return 0;
	}
	print STDERR "Testing for Rscript...\n";
	system("Rscript -e \"print('ok')\" > gigt");
	if (!open(IN, "<gigt")) {
		print STDERR "File not found, Rscript test failed...\n";
		return 0;
	}
	my $in = <IN>;

	if ($in =~ /\"ok\"/) {
		print STDERR "Rscript ok\n";
		return 1;
	}
	print STDERR "Unexpected output, Rscript test failed...\n";
	return 0;
}

#}}}
