/***************************************************************

   The Subread software package is free software package:
   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 3 of the License,
   or (at your option) any later version.

   Subread 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.

   Authors: Drs Yang Liao and Wei Shi

  ***************************************************************/

#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "LRMconfig.h"
#include "LRMchro-event.h"
#include "LRMfile-io.h"
#include "LRMbase-index.h"
#include "LRMhelper.h"

#define JUNCTION_CONFIRM_WINDOW 14

#define ceq(c,t) ((c)[0]==(t)[0] && (c)[1]==(t)[1])
#define c2eq(ch1, ch2, tg1, tg2) ((ceq(ch1, tg1) && ceq(ch2, tg2)) || (ceq(ch1, tg2) && ceq(ch2, tg1)) )

#define LRMis_donor_chars(cc) (((cc)[0]=='G' && (cc)[1]=='T') || \
			    ((cc)[0]=='A' && (cc)[1]=='G') || \
			    ((cc)[0]=='A' && (cc)[1]=='C') || \
			    ((cc)[0]=='C' && (cc)[1]=='T') ||\
			    ((cc)[0]=='G' && (cc)[1]=='C')) 
				

int LRMpaired_chars(char * ch1, char * ch2){
	if (c2eq(ch1, ch2, "GC", "AG") || c2eq(ch1, ch2, "GT", "AG") || c2eq(ch1, ch2, "CT", "AC")) {
		if ( ceq(ch1, "GC") || ceq(ch1, "CT") || ceq(ch1, "GT")) return 1;
	}
	return 0;
}


int LRMscanning_events_compare(void * arr, int l, int r){
	void ** arrr = (void **) arr;
	LRMcontext_t * context = arrr[0];
	int * event_ids = arrr[1];
	LRMevent_t * body_l = context -> event_space+event_ids[l];
	LRMevent_t * body_r = context -> event_space+event_ids[r];

	if(body_l->small_side > body_r->small_side)return 1;
	if(body_l->small_side < body_r->small_side)return -1;
	
	if(body_l->large_side > body_r->large_side)return 1;
	if(body_l->large_side < body_r->large_side)return -1;

	if(body_l->event_type > body_r->event_type) return 1;
	if(body_l->event_type < body_r->event_type) return -1;
	
	if(body_l -> indel_length > body_r -> indel_length) return -1; // same length, but L is del and R is ins -- prefer del than ins
	if(body_l -> indel_length < body_r -> indel_length) return 1;
	
	return -1;
}

void LRMscanning_events_merge(void * arr,  int start, int items, int items2){
	void ** arrr = (void **) arr;
	int * records = arrr[1];

	int read_1_ptr = start, read_2_ptr = start+items, write_ptr;
	int * merged_records = malloc(sizeof(int) * (items+items2));

	for(write_ptr=0; write_ptr<items+items2; write_ptr++){
		if((read_1_ptr >= start+items)||(read_2_ptr < start+items+items2 && LRMscanning_events_compare(arr, read_1_ptr, read_2_ptr) > 0))
			merged_records[write_ptr] = records[read_2_ptr++];
		else
			merged_records[write_ptr] = records[read_1_ptr++];
	}	
	memcpy(records + start, merged_records, sizeof(int) * (items+items2));
	free(merged_records);
}

void LRMscanning_events_exchange(void * arr, int l, int r){
	void ** arrr = (void **) arr;
	int * records = arrr[1];

	int tmpi;

	tmpi = records[l];
	records[l] = records[r];
	records[r] = tmpi;
}

int LRMevents_build_entries(LRMcontext_t  * context){
	int x1,side_i;

	for(x1=0; x1 < context->event_number; x1++){
		LRMevent_t * te = context->event_space+ x1;
		for(side_i = 0; side_i <2; side_i++){
			unsigned int sidepos = side_i?te->large_side:te->small_side;
			int * entries_list = HashTableGet(context -> events_realignment, NULL+sidepos);
			//LRMprintf("INSERT ENTRY : %u -> %p ; SRC: %u ~ %u\n", sidepos, entries_list, te->small_side, te->large_side);
			if(NULL == entries_list){
				entries_list = malloc(sizeof(int) * 3);
				if(!entries_list){
					LRMprintf("ERROR: NO MEMORY CAN BE ALLOCATED!\n");
					assert(0);
				}
				entries_list[0]=2;
				entries_list[1]=0;
				HashTablePut(context -> events_realignment , NULL+sidepos, entries_list);
			}
			int x2 = 0, inserted = 0;
			for(x2=1; x2< 1+ min( LRMMAX_EVENTS_PER_SITE , entries_list[0] ); x2++){
				//#warning ">>>>>>>>> COMMENT NEXT LINE <<<<<<<<"
				//if( x1 + 1 == entries_list[x2] )LRMprintf("REPEATED ENTRY: %d\n");

				if(0 == entries_list[x2]){
					entries_list[x2] = x1+1;
					if( x2 < entries_list[0] )entries_list[x2+1]=0;
					inserted = 1;
					break;
				}
			}
			if((!inserted) && entries_list[0] < LRMMAX_EVENTS_PER_SITE){
				int last_x1 = entries_list[0];
				entries_list[0] = LRMMAX_EVENTS_PER_SITE;
				entries_list = realloc(entries_list, sizeof(int)*(1+LRMMAX_EVENTS_PER_SITE));
				entries_list[last_x1] = x1+1;
				entries_list[last_x1+1] = 0;

				if(te -> small_side == 457511654 ) LRMprintf("INSERT_NEW EVENT : %d AT %u\n",x1, sidepos );
				
				HashTablePut(context -> events_realignment, NULL+sidepos, entries_list);
			}
		}
	}
	return 0;
}

void LRMevents_reorder_merge_next(LRMcontext_t * context, int *order_index){
	LRMevent_t *prev_event = NULL, * new_space = malloc(sizeof(LRMevent_t) * 10000);
	int x1, new_space_size = 10000, new_space_used = 0;

	for(x1=0; x1 <=context->event_number; x1++){
		LRMevent_t *this_event = NULL;
		if(x1 < context->event_number) this_event = context->event_space+order_index[x1];
		if( x1 < context->event_number && prev_event!=NULL &&
			prev_event->large_side == this_event->large_side &&
			prev_event->small_side == this_event->small_side &&
			prev_event->event_type == this_event->event_type &&
			prev_event->indel_length == this_event->indel_length){
			prev_event -> supporting_reads ++;
		}else{
			if(new_space_size -1 < new_space_used){
				new_space_size*=1.7;
				new_space = realloc(new_space, sizeof(LRMevent_t)*new_space_size);
			}
			if(prev_event) memcpy(new_space+(new_space_used++), prev_event, sizeof(LRMevent_t));

			if(this_event){
				prev_event = this_event;
				prev_event -> supporting_reads = 1;
			}
		}
	}

	free(context -> event_space);
	context -> event_space = new_space;
	context -> event_space_size = new_space_size;
	context -> event_number = new_space_used;
}

int LRMevents_reorder(LRMcontext_t * context){
	int * order_index = malloc(context -> event_number*sizeof(int));
	int x1=0;
	while(x1<context -> event_number){
		order_index[x1]=x1;
		x1++;
	}
	void * sort_arr[2];
	sort_arr [0] = context;
	sort_arr [1] = order_index;
	
	merge_sort(sort_arr, context -> event_number, LRMscanning_events_compare, LRMscanning_events_exchange, LRMscanning_events_merge);
	//basic_sort(sort_arr, context -> event_number, LRMscanning_events_compare, LRMscanning_events_exchange);
	LRMevents_reorder_merge_next(context, order_index);
	
	if(0){
		LRMprintf("Total events : %d\n", context -> event_number);
		for(x1=0; x1<context -> event_number; x1++){
			LRMevent_t * te = context->event_space+ x1;
			if(1 || te -> small_side == 457511654){

				char pos1txt[100], pos2txt[100];
				LRMpos2txt(context, te->small_side, pos1txt);
				LRMpos2txt(context, te->large_side, pos2txt);

				LRMprintf("SORTED EVENT: TYPE: %d - INS %d %s ~ %s, nsup=%d\n", te -> event_type, te -> indel_length, pos1txt, pos2txt, te->supporting_reads);
			}
		}
	}

	free(order_index);
	return 0;
}

int LRMchro_event_new(LRMcontext_t * context, LRMthread_context_t * thread_context, LRMread_iteration_context_t * iteration_context, LRMevent_t * new_event){
	if(new_event -> event_type == LRMEVENT_TYPE_INDEL) return 0;

	LRMthread_lock(&context -> event_space_lock);
	if(context -> event_space_size < context -> event_number + 1 ){
		context -> event_space_size *= 1.7;
		context -> event_space =realloc(context -> event_space, sizeof(LRMevent_t) * context -> event_space_size);
		if(!context -> event_space )return 1;
	}
	memcpy(context -> event_space+context -> event_number, new_event, sizeof(LRMevent_t));
	context -> event_number++;
	//LRMprintf("Total events after adding : %d\n", context -> event_number);
	LRMthread_lockrelease(&context -> event_space_lock);
	
	return 0;
}

#define LRMDP_score(x,y) dynamic_score_buffer[ (x)*dynamic_row_width + (y) ]
#define LRMDP_move(x,y) dynamic_movement_BEFORE_buffer[ (x)*dynamic_row_width + (y) ]

int tested = 0;

void LRMindel_dynamic_search_debug(LRMcontext_t* context, int * dynamic_score_buffer, char * dynamic_movement_BEFORE_buffer, int dynamic_row_width, int  dynamic_rows, int *best_offset_history){
	int rr, ii;

	LRMprintf("     ");
	for(ii=0;ii<dynamic_row_width;ii++)
		LRMprintf("  % 4d  ", ii - context -> max_dynamic_indel_length);
	LRMprintf("\n");
	
	for(rr=0; rr<dynamic_rows; rr++){
		LRMprintf("%4d | %4d ", best_offset_history?best_offset_history[ rr ]:-1, rr);
		for(ii=0;ii<dynamic_row_width;ii++){
			LRMprintf("% 4d %c  ", LRMDP_score(rr,ii), LRMDP_move(rr,ii));
		}
		LRMprintf("\n");
	}
}

#define LRMSOFTCLIPPING_WINDOW 30
#define LRMSOFTCLIPPING_MATCHED 25
int LRMsoftclipping_moves(LRMcontext_t* context, LRMthread_context_t* thread_context, char * move_buff, int moves, int bases_in_read){
	int ii;
	
	int included_read_length = 0;
	int last_M = 0x7fffffff;
	int window_end = moves - 1;
	int window_start = 0;
	int window_MX = 0, window_M=0;


	//LRMprintf("MOVES=%s\n", move_buff);
	for(ii = moves -1; ii>= 0; ii--){
		if( move_buff[ii] == 'M' || move_buff[ii] == 'X' ){
			window_MX++;
			if(move_buff[ii] == 'M')
				window_M++;
		}
		if(window_MX == LRMSOFTCLIPPING_WINDOW)break;
	}
	window_start = ii;

	if(window_MX ==LRMSOFTCLIPPING_WINDOW){
		for(; window_start >=0 ; window_start--){
			if(move_buff[window_start]=='M' || move_buff[window_start] =='X'){
				window_MX ++;
				if(move_buff[window_start]=='M')
					window_M++;
			}

			if(window_MX > LRMSOFTCLIPPING_WINDOW){
				while(1){
					char nch = move_buff[window_end--];
					if(nch == 'M' || nch == 'X'){
						window_MX --;
						if(nch == 'M') window_M--;
						break;
					}
				}
			}

			//LRMprintf("M=%d, W = %d - %d, windows_MX=%d in %d\n", window_M, window_start, window_end, window_MX, bases_in_read);
			if(window_M < LRMSOFTCLIPPING_MATCHED)
				break;
		}
	}

	int smallwindow_Xs = 0;
	last_M = window_end;

	for(ii = window_end; ii>=0 && ii >= window_start; ii--){
		if(move_buff[ii] == 'M')
			last_M = ii;

		if(move_buff[ii] == 'X' && window_M < LRMSOFTCLIPPING_MATCHED){
			smallwindow_Xs++;
			if(smallwindow_Xs > 1) break;
		}
	}

	//LRMprintf("M=%d, last 'M' at %d, windows_MX=%d in %d\n", window_M, last_M, window_MX, bases_in_read);
	for(ii = moves -1; ii>= last_M; ii--){
		if(move_buff[ii] == 'M' || move_buff[ii] == 'X' || move_buff[ii] == 'I')
			included_read_length++;
	}

	//assert( (last_M - 1) >=(bases_in_read - included_read_length));
	//LRMprintf("last_M=%d, included_read_length=%d in %d\n", last_M, included_read_length, bases_in_read );
	for(ii = last_M - 1; ii > (last_M - 1) - (bases_in_read - included_read_length) ; ii--){
		if(ii<0) return -1;
		move_buff[ii]='S';
	}

	for(; ii >= 0; ii--)
		move_buff[ii]='.';
	return 0;
} 



#define LRMindel_dynamic_search_narrow LRMindel_dynamic_search 
//#define LRMindel_dynamic_search_full LRMindel_dynamic_search 

int my_debug = 0;
int LRMindel_dynamic_search_narrow(LRMcontext_t* context, LRMthread_context_t* thread_context, int expected_indels, unsigned int last_correct_base_on_chro, char * corrected_read, int last_correct_base, int first_correct_base,unsigned int * total_mismatched_bases, int high_penalty_create_gap, char * read_name){
	int moves, xx1;

	(*total_mismatched_bases)=0;
	if(my_debug) {
		char postxt[100];
		LRMpos2txt(context, last_correct_base_on_chro, postxt);
		LRMprintf("Dynamic: at %s : %d - %d ; expected = %d\n", postxt, last_correct_base, first_correct_base, expected_indels);
		for(xx1 = 0 ; xx1 < first_correct_base -  last_correct_base ; xx1++ ){
			LRMprintf("%c", corrected_read[ xx1 + last_correct_base ]);
		}
		LRMprintf("\n");
		for(xx1 = 0 ; xx1 < first_correct_base -  last_correct_base - expected_indels; xx1++){
			LRMprintf("%c", LRMgvindex_get(& context -> current_base_index,  last_correct_base_on_chro + xx1));
		}
		LRMprintf("\n");
	}

	int dynamic_rows = first_correct_base - last_correct_base;
	int trying_indel_length = LRMINDEL_DYNAMIC_CHANNEL_TOLERANCE;
	
	int best_offset_history [dynamic_rows];
	int score_match = context -> dynamic_programming_score_match;
	int score_mismatch = context -> dynamic_programming_score_mismatch;
	int score_create_gap = context -> dynamic_programming_score_create_gap * (1+high_penalty_create_gap);
	int score_extend_gap = context -> dynamic_programming_score_extend_gap;
	int dynamic_row_width = 2* trying_indel_length + 1;

//	assert(dynamic_rows <=LRMDYNAMIC_MAXIMUM_GAP_LENGTH);

	//LRMprintf("DYNAMIC SCORING BUFF = %lld bytes (%d * %d)\n",  sizeof(int) * dynamic_row_width * dynamic_rows, dynamic_row_width, dynamic_rows);
	int * dynamic_score_buffer = (int *)thread_context -> dynamic_programming_score_buffer;
	char * dynamic_movement_BEFORE_buffer = thread_context -> dynamic_programming_movement_buffer;
	//LRMprintf("SETTING 0 TO %p : %lu bytes\n", dynamic_score_buffer,sizeof(int) * dynamic_row_width * dynamic_rows);
	memset(dynamic_score_buffer, 0, sizeof(int) * dynamic_row_width * dynamic_rows);
	memset(dynamic_movement_BEFORE_buffer, 0, sizeof(char) * dynamic_row_width * dynamic_rows);
	char * indel_movement_buff = (char *) thread_context -> dynamic_programming_indel_movement_buf;
	
	LRMDP_score(0,  trying_indel_length  )=0;
	int read_cursor = last_correct_base, row_i, indel_i;
	unsigned int chro_cursor = last_correct_base_on_chro;

	int last_slope_offset = 0;

	if(1){
		float slope = expected_indels *1. / dynamic_rows;
		for(xx1 = 0; xx1 < dynamic_rows; xx1++)
		//#warning "========= DELETE 0* ============="
			best_offset_history[xx1] = 1* (int)(xx1 * slope);
	}

	for(; read_cursor < first_correct_base; read_cursor++){
		row_i = read_cursor - last_correct_base;
		int slope_offset = row_i>0?best_offset_history[row_i-1]:0;
		int last_slope_delta = slope_offset - last_slope_offset;

		//LRMprintf("Filling Dynamic Matrix : row %d / %d\n", read_cursor, first_correct_base - min(0, expected_indels));
		for(indel_i = dynamic_row_width-1 ; indel_i >=0; indel_i --){ // negative: deletion; positive: insertion
			int testing_indel = indel_i - trying_indel_length;
			if(1){
				int score_from_del = -0x7fffffff, score_from_ins = -0x7fffffff, score_from_match = -0x7fffffff;
				//int is_matched_base = toupper(corrected_read[read_cursor + max(0, testing_indel)]) == toupper(LRMgvindex_get(& context -> current_base_index, chro_cursor - min(0, testing_indel) ));
				int is_matched_base = toupper(corrected_read[read_cursor]) == toupper(LRMgvindex_get(& context -> current_base_index, chro_cursor - slope_offset - testing_indel));

				if(row_i>0 && (indel_i-1+ last_slope_delta)>=0 && (indel_i-1+ last_slope_delta)< dynamic_row_width && LRMDP_score(row_i-1, indel_i-1 + last_slope_delta) > -0x7ffffff0)
					score_from_ins = LRMDP_score(row_i-1, indel_i-1 + last_slope_delta) + ( (LRMDP_move(row_i-1, indel_i-1+ last_slope_delta) == 'M' || LRMDP_move(row_i-1, indel_i-1 +last_slope_delta) == 'X')?score_create_gap:score_extend_gap);

				if(testing_indel < 0 || testing_indel < row_i)if(indel_i < dynamic_row_width-1 && LRMDP_score(row_i, indel_i+1) > -0x7ffffff0)
					score_from_del = LRMDP_score(row_i, indel_i+1) + ((LRMDP_move(row_i, indel_i+1) == 'M' || LRMDP_move(row_i, indel_i+1) == 'X')?score_create_gap:score_extend_gap);

				if((indel_i+ last_slope_delta)>=0 && (indel_i+ last_slope_delta)< dynamic_row_width && (row_i ==0 || LRMDP_score(row_i-1, indel_i + last_slope_delta) > -0x7ffffff0)){
  					score_from_match =(row_i > 0 ?LRMDP_score(row_i-1, indel_i + last_slope_delta): 0)+ (is_matched_base?score_match:score_mismatch);
					if(row_i == 0 && testing_indel > 0) score_from_match += score_create_gap + (testing_indel-1) * score_extend_gap;
				}
				
				int final_score = max(score_from_del, max(score_from_ins, score_from_match));
				if(testing_indel + slope_offset > 0 && row_i < slope_offset + testing_indel){
					LRMDP_score(row_i, indel_i) = score_create_gap + (score_extend_gap-1)  * (testing_indel+slope_offset) ;
					LRMDP_move(row_i, indel_i) =  'I'; 
				}else{
					LRMDP_score(row_i, indel_i) = final_score;
					if(final_score < -0x7ffffff0) LRMDP_move(row_i, indel_i) = '?';
					else LRMDP_move(row_i, indel_i) = score_from_del == final_score?'D':((score_from_ins == final_score)?'I': ( is_matched_base ?'M':'X'));
				}
			}
		}
		last_slope_offset = slope_offset;
		chro_cursor ++;
	}

	if(my_debug) LRMindel_dynamic_search_debug(context, dynamic_score_buffer, dynamic_movement_BEFORE_buffer, dynamic_row_width, dynamic_rows, best_offset_history);

	row_i = first_correct_base - last_correct_base - 1;
	indel_i = trying_indel_length + expected_indels -(row_i >0?best_offset_history[row_i - 1]:0);

	moves = 0;
	while(row_i >= 0 && indel_i >=0 && indel_i < dynamic_row_width){
		int slope_offset =  best_offset_history[row_i-1];
		int next_slope_offset = row_i > 1?best_offset_history[row_i-2]:0;
		int last_slope_delta = slope_offset - next_slope_offset;
		//#warning "========= DO NOT ASSERT ============="
		indel_movement_buff[moves] = LRMDP_move(row_i, indel_i);
		if(indel_movement_buff[moves]=='?')LRMprintf("Assertion_Error:%s\n", read_name);
		assert(indel_movement_buff[moves]!='?');
		(* total_mismatched_bases) += (indel_movement_buff[moves]=='X')?1:0;

		if(indel_movement_buff[moves] == 'M' || indel_movement_buff[moves] == 'X'){
			row_i--;
			indel_i += last_slope_delta;
		} else if(indel_movement_buff[moves] == 'D')indel_i++;
		  else {
			indel_i --;
			indel_i += last_slope_delta;
			row_i--;
		}
		moves ++;

		if(row_i < 0 && indel_i < trying_indel_length)
			for(; indel_i < trying_indel_length; indel_i++) indel_movement_buff[moves++] ='D';

		if(moves > max( LRMDYNAMIC_MAXIMUM_GAP_LENGTH * 15, 300 ) +  context -> max_dynamic_indel_length ){
			LRMprintf("ERROR: Dynamic programming moves more than %d\n",  max( (int)(LRMDYNAMIC_MAXIMUM_GAP_LENGTH * 15), 300 ) +  context -> max_dynamic_indel_length);
			return -1;
		}
	}
	
	indel_movement_buff[moves]=0;
	//if(my_debug)LRMprintf("MOVE0 = %s\n", indel_movement_buff);
	for(row_i = 0; row_i < moves/2; row_i++){
		char tmp = indel_movement_buff[row_i];
		indel_movement_buff[row_i] = indel_movement_buff[ moves - row_i - 1];
		indel_movement_buff[ moves - row_i - 1] = tmp;
	}
	if(my_debug)LRMprintf("MOVES = %s\n", indel_movement_buff);

	//#warning "=============== DO NOT EXIT ==========="
	//if(tested ++ > 26) exit(0);
	return moves;
}


int LRMindel_dynamic_search_unknownregion(LRMcontext_t* context, LRMthread_context_t* thread_context, int search_to_3end, unsigned int last_correct_base_on_chro, char * corrected_read, int last_correct_base, int first_correct_base,unsigned int * total_mismatched_bases, int high_penalty_create_gap, char * read_name){
	int moves;
	(*total_mismatched_bases)=0;

	int bases_in_read = first_correct_base - last_correct_base;
	int trying_indel_length = LRMINDEL_DYNAMIC_CHANNEL_TOLERANCE;
	
	int best_offset_history [bases_in_read];
	int score_match = context -> dynamic_programming_score_match;
	int score_mismatch = context -> dynamic_programming_score_mismatch;
	int score_create_gap = context -> dynamic_programming_score_create_gap * (1+high_penalty_create_gap);
	int score_extend_gap = context -> dynamic_programming_score_extend_gap;
	int dynamic_row_width = 2* trying_indel_length + 1;

	int * dynamic_score_buffer = (int *)thread_context -> dynamic_programming_score_buffer;
	char * dynamic_movement_BEFORE_buffer = thread_context -> dynamic_programming_movement_buffer;
	memset(dynamic_score_buffer, 0, sizeof(int) * dynamic_row_width * bases_in_read);
	memset(dynamic_movement_BEFORE_buffer, 0, sizeof(char) * dynamic_row_width * bases_in_read);
	char * indel_movement_buff = (char *) thread_context -> dynamic_programming_indel_movement_buf;
	
	LRMDP_score(0,  trying_indel_length  )=0;
	unsigned int chro_cursor ;

	int last_slope_offset = 0, read_i, indel_i, previous_base_in_read = 0;

	if(0 && !search_to_3end){
		char postxt[100];
		LRMpos2txt(context, last_correct_base_on_chro, postxt);
		LRMprintf("EXTEND_UNKNOWN: %s\n", postxt);
		if(!search_to_3end){
				int bb;
				bb = corrected_read[first_correct_base];
				corrected_read[first_correct_base] = 0;
				LRMprintf("READ:           %s\n", corrected_read);
				corrected_read[first_correct_base] = bb;

				LRMprintf("CHRO: ");
				for(chro_cursor = last_correct_base_on_chro - bases_in_read - 10; chro_cursor < last_correct_base_on_chro; chro_cursor ++){
					bb = LRMgvindex_get(& context -> current_base_index, chro_cursor);
					LRMprintf("%c", bb);
				}
				LRMprintf("\n\n");
		}else{
				int bb;
				bb = corrected_read[first_correct_base];
				corrected_read[first_correct_base] = 0;
				LRMprintf("READ: %s\n", corrected_read + last_correct_base);
				corrected_read[first_correct_base] = bb;

				LRMprintf("CHRO: ");
				for(chro_cursor = last_correct_base_on_chro; chro_cursor < last_correct_base_on_chro + 10 + bases_in_read; chro_cursor ++){
					bb = LRMgvindex_get(& context -> current_base_index, chro_cursor);
					LRMprintf("%c", bb);
				}
				LRMprintf("\n\n");
		}
	}

	for(read_i = 0; read_i < bases_in_read; read_i ++){
		int this_base_in_read = search_to_3end? read_i :(bases_in_read - read_i -1);
		int this_base_value_in_read = corrected_read [ last_correct_base + this_base_in_read ];

		int slope_offset = read_i>0?best_offset_history[previous_base_in_read]:0;
		int last_slope_delta = slope_offset - last_slope_offset;
		if(0 && ! search_to_3end)LRMprintf("GET READ_BASE='%c' LAST_OFF=%d  SLP_OFF=%d  LAST_DELTA=%d\n", this_base_value_in_read, last_slope_offset, slope_offset, last_slope_delta);
		
		int thisrow_max_score = -0x7fffffff, thisrow_max_indel_from_start = -0x7fffffff;

	
		for(indel_i = search_to_3end?dynamic_row_width-1 : 0; indel_i !=(search_to_3end?-1:dynamic_row_width); indel_i+=(search_to_3end?-1:1)){
			int indel_from_start = slope_offset + ( indel_i - trying_indel_length);	// if to_3end: +:ins, -:del;  if !to_3end: +:del, -:ins
			unsigned int chro_location_after_indel = last_correct_base_on_chro + ( search_to_3end ?( read_i):(- read_i -1)) - indel_from_start; // if !to_3end: "DEL" from right is "INS" from left
			int this_base_value_in_chro = LRMgvindex_get(& context -> current_base_index, chro_location_after_indel);

			int score_from_del = -0x7fffffff, score_from_ins = -0x7fffffff, score_from_match = -0x7fffffff;
			int is_matched_base = toupper(this_base_value_in_read)== toupper(this_base_value_in_chro);


			if(search_to_3end){
					if(read_i > 0 && indel_i-1 + last_slope_delta >=0 && indel_i-1 + last_slope_delta < dynamic_row_width && read_i > 0 && LRMDP_score(read_i-1, indel_i-1 + last_slope_delta) > -0x7ffffff0)
						score_from_ins = LRMDP_score(read_i - 1, indel_i-1 + last_slope_delta) + ( (LRMDP_move(read_i - 1, indel_i-1+ last_slope_delta) == 'I')?score_extend_gap:score_create_gap);

					if( indel_from_start < 0 || indel_from_start < read_i ) if(indel_i < dynamic_row_width-1 && read_i > 0 && LRMDP_score(read_i, indel_i+1) > -0x7ffffff0)
						score_from_del = LRMDP_score(read_i, indel_i+1) + ((LRMDP_move(read_i, indel_i+1) == 'D')?score_extend_gap:score_create_gap);

					if((indel_i+ last_slope_delta)>=0 && (indel_i+ last_slope_delta)< dynamic_row_width && (read_i ==0 || LRMDP_score(read_i-1, indel_i + last_slope_delta) > -0x7ffffff0))
						score_from_match =(read_i > 0 ?LRMDP_score(read_i-1, indel_i + last_slope_delta): 0)+ (is_matched_base?score_match:score_mismatch);
					//if(read_i == 2) LRMprintf("INDEL_i=%d, F_INS=%d, F_DEL=%d, F_MAT=%d\n", indel_i, score_from_ins, score_from_del, score_from_match);
			}else{
					if( indel_from_start > 0 || ( -indel_from_start < read_i ) ) if(indel_i>0 && LRMDP_score(read_i, indel_i-1) > -0x7ffffff0)
						score_from_ins = LRMDP_score(read_i, indel_i-1) + ( (LRMDP_move(read_i, indel_i-1) == 'I')?score_extend_gap:score_create_gap);

					if(indel_i < dynamic_row_width-1 && indel_i+1 + last_slope_delta >= 0 && indel_i+1 + last_slope_delta < dynamic_row_width  && read_i > 0 && LRMDP_score(read_i - 1, indel_i+1+last_slope_delta) > -0x7ffffff0)
						score_from_del = LRMDP_score(read_i - 1, indel_i+1 + last_slope_delta) + ((LRMDP_move(read_i - 1, indel_i+1+last_slope_delta) == 'D')?score_extend_gap:score_create_gap);

					if((indel_i+ last_slope_delta)>=0 && (indel_i+ last_slope_delta)< dynamic_row_width && (read_i ==0 || LRMDP_score(read_i-1, indel_i + last_slope_delta) > -0x7ffffff0))
						score_from_match =(read_i > 0 ?LRMDP_score(read_i-1, indel_i + last_slope_delta): 0)+ (is_matched_base?score_match:score_mismatch);
					//if(read_i == 4 && !search_to_3end) // LRMprintf("INDEL_i=%d, F_INS=%d, F_DEL=%d, F_MAT=%d\n", indel_i, score_from_ins, score_from_del, score_from_match);
					//	LRMprintf("SCORE AT readi=%d, indel_i=%d = %d ;; MOVE = '%c'\n", read_i, indel_i-1+ last_slope_delta, LRMDP_score(read_i, indel_i-1+ last_slope_delta), LRMDP_move(read_i, indel_i-1+ last_slope_delta));
			}

			if(read_i == 0 && indel_from_start > 0 && !search_to_3end) score_from_match += score_create_gap + (indel_from_start-1) * score_extend_gap;
			if(read_i == 0 && indel_from_start > 0 &&  search_to_3end) score_from_match += score_create_gap + (indel_from_start-1) * score_extend_gap;

			int final_score = max(score_from_del, max(score_from_ins, score_from_match));
			//if(read_i == 4 && !search_to_3end)LRMprintf(" == READ_I %d; INDEL_I %d; INDEL_START %d; FINAL %d\n", read_i, indel_i, indel_from_start, final_score);

			if(indel_from_start < 0 && read_i < - indel_from_start && !search_to_3end){
				LRMDP_score(read_i, indel_i) = score_create_gap - score_extend_gap  * indel_from_start ;
				LRMDP_move(read_i, indel_i) =  'D';
			} else if(indel_from_start > 0 && read_i < indel_from_start && search_to_3end) {
				LRMDP_score(read_i, indel_i) = score_create_gap + score_extend_gap  * (indel_from_start -1) ;
				LRMDP_move(read_i, indel_i) =  'I';
			} else if(final_score < -0x7ffffff0){
				LRMDP_move( read_i, indel_i) = '?';
			}else{ 
				if(0 && ! search_to_3end)LRMprintf("#%d %c%c%c %c %d |", indel_i, indel_from_start?' ':'>', this_base_value_in_chro, indel_from_start?' ':'<', score_from_del == final_score?'D':((score_from_ins == final_score)?'I': ( is_matched_base ?'M':'X')), final_score);
				LRMDP_score( read_i, indel_i) = final_score;
				//LRMprintf(" !! READ_I %d; INDEL_I %d; INDEL_START %d; FINAL %d\n", read_i, indel_i, indel_from_start, final_score);
				if(final_score > thisrow_max_score && abs( indel_i - dynamic_row_width/2 ) < dynamic_row_width/3){
					thisrow_max_score = final_score;
					thisrow_max_indel_from_start = indel_from_start;
				}
				LRMDP_move(read_i, indel_i) =(score_from_del == final_score?'D':((score_from_ins == final_score)?'I': ( is_matched_base ?'M':'X')));
			}
		}
		//if(thisrow_max_indel_from_start < -0x7ffffff0) LRMprintf("ERROR READ\n");
		//else LRMprintf("      READ\n");
		if(thisrow_max_indel_from_start < -0x7ffffff0 && read_name){
			LRMprintf(" !! BADREAD:%s\n",read_name);
		}
		assert(thisrow_max_indel_from_start > -0x7ffffff0);
		best_offset_history[this_base_in_read] = thisrow_max_indel_from_start;
		if(0 && ! search_to_3end)LRMprintf("\nSET %d-th BEST_FROM_START=%d ;  SLOPE_OFFSET=%d ;  MAX_SCORE=%d\n\n", this_base_in_read, thisrow_max_indel_from_start, slope_offset, thisrow_max_score);

		last_slope_offset = slope_offset;
		previous_base_in_read = this_base_in_read;
	}
	read_i = bases_in_read - 1;

	//LRMprintf("RESTART SEARCH: best_offset_history[read_i]=%d, best_offset_history[read_i-1]=%d\n", best_offset_history[  search_to_3end? bases_in_read - 1 : 0 ] - best_offset_history[ search_to_3end? bases_in_read - 2 : 1 ] );
	indel_i = best_offset_history[  search_to_3end? bases_in_read - 1 : 0 ] - best_offset_history[ search_to_3end? bases_in_read - 2 : 1 ] + trying_indel_length;

	moves = 0;
	int error_in = 0;
	while(read_i >= 0 && indel_i >=0 && indel_i < dynamic_row_width){
		int real_base_in_read = search_to_3end? read_i:(bases_in_read - (read_i+1));
		int slope_offset;
		int next_slope_offset;

		if(search_to_3end){
			slope_offset = (real_base_in_read>0)?best_offset_history[real_base_in_read - 1]:0;
			next_slope_offset = (real_base_in_read>1)?best_offset_history[real_base_in_read - 2]:0;
		}else{
			slope_offset = (real_base_in_read<bases_in_read - 1)?best_offset_history[real_base_in_read + 1]:0;
			next_slope_offset = (real_base_in_read<bases_in_read - 2)?best_offset_history[real_base_in_read + 2]:0;
		}

		int last_slope_delta = next_slope_offset - slope_offset;
		//#warning "========= DO NOT ASSERT ============="
		indel_movement_buff[moves] = LRMDP_move(read_i, indel_i);
		//LRMprintf("R %d , SCORE+=%d (INDEL_i=%d)  MOVE='%c'  LAST_DELTA=%d\n", read_i, LRMDP_score(read_i, indel_i), indel_i, LRMDP_move(read_i, indel_i), last_slope_delta);
		if(indel_movement_buff[moves]=='?'){
			error_in = 1;
			//LRMprintf("READ_ERROR_MOVE : %s\n", read_name);
			break;
		}
		(* total_mismatched_bases) += (indel_movement_buff[moves]=='X')?1:0;


		if(indel_movement_buff[moves] == 'M' || indel_movement_buff[moves] == 'X'){
			read_i--;
			if(read_i>=0)indel_i -= last_slope_delta;
		}else {

			if(search_to_3end){
				if(indel_movement_buff[moves] == 'D')indel_i++;
				else {
					indel_i --;
					if(read_i>=0)indel_i -= last_slope_delta;
					read_i--;
				}
			}else{
				if(indel_movement_buff[moves] == 'I')indel_i--;
				else {
					indel_i ++;
					if(read_i>=0)indel_i -= last_slope_delta;
					read_i--;
				}
			}
		}
		moves ++;

		//if(read_i<0) LRMprintf("END_UP: indel_i = %d > %d\n", indel_i, trying_indel_length);
		if(search_to_3end){
			if(read_i < 0 && indel_i < trying_indel_length)
				for(; indel_i <trying_indel_length; indel_i++) indel_movement_buff[moves++] = 'D';
		}else if(read_i < 0 && indel_i > trying_indel_length)
			for(; indel_i > trying_indel_length; indel_i--) indel_movement_buff[moves++] = 'I';

		if(moves > max( LRMDYNAMIC_MAXIMUM_GAP_LENGTH * 15, 300 ) +  context -> max_dynamic_indel_length ){
			LRMprintf("ERROR: Dynamic programming moves more than %d\n",  max( (int)(LRMDYNAMIC_MAXIMUM_GAP_LENGTH * 15), 300 ) +  context -> max_dynamic_indel_length);
			return -1;
		}
	}

	if(error_in)return -1;

	indel_movement_buff[moves]=0;
	if(!search_to_3end){
		for(read_i = 0; read_i < moves; read_i++){
			char tmp = indel_movement_buff[read_i];
			if(tmp == 'I') indel_movement_buff[read_i]='D';
			else if(tmp == 'D') indel_movement_buff[read_i]='I';
		}
	}

	
	error_in = LRMsoftclipping_moves(context,thread_context,indel_movement_buff, moves, bases_in_read);
	if(error_in) return -1;

	if(search_to_3end){
		//if(my_debug)LRMprintf("MOVE0 = %s\n", indel_movement_buff);
		for(read_i = 0; read_i < moves/2; read_i++){
			char tmp = indel_movement_buff[read_i];
			indel_movement_buff[read_i] = indel_movement_buff[ moves - read_i - 1];
			indel_movement_buff[ moves - read_i - 1] = tmp;
		}
	}
	return moves;
}

int LRMindel_dynamic_search_full(LRMcontext_t* context, LRMthread_context_t* thread_context, int expected_indels, unsigned int last_correct_base_on_chro, char * corrected_read, int last_correct_base, int first_correct_base,unsigned int * total_mismatched_bases){
	int moves, xx1;

	(*total_mismatched_bases)=0;
	if(my_debug) {
		char postxt[100];
		LRMpos2txt(context, last_correct_base_on_chro, postxt);
		LRMprintf("Dynamic: at %s : %d - %d ; expected = %d\n", postxt, last_correct_base, first_correct_base, expected_indels);
		for(xx1 = 0 ; xx1 < first_correct_base -  last_correct_base ; xx1++ ){
			LRMprintf("%c", corrected_read[ xx1 + last_correct_base ]);
		}
		LRMprintf("\n");
		for(xx1 = 0 ; xx1 < first_correct_base -  last_correct_base - expected_indels; xx1++){
			LRMprintf("%c", LRMgvindex_get(& context -> current_base_index,  last_correct_base_on_chro + xx1));
		}
		LRMprintf("\n");
	}

	int trying_indel_length = min(context -> max_dynamic_indel_length, max(16, abs(expected_indels) *5/3));
	//trying_indel_length = context -> max_dynamic_indel_length;
	
	int score_match = context -> dynamic_programming_score_match;
	int score_mismatch = context -> dynamic_programming_score_mismatch;
	int score_create_gap = context -> dynamic_programming_score_create_gap;
	int score_extend_gap = context -> dynamic_programming_score_extend_gap;
	int dynamic_row_width = 2* trying_indel_length + 1;
	int dynamic_rows = first_correct_base - last_correct_base;

//	assert(dynamic_rows <=LRMDYNAMIC_MAXIMUM_GAP_LENGTH);

	//LRMprintf("DYNAMIC SCORING BUFF = %lld bytes (%d * %d)\n",  sizeof(int) * dynamic_row_width * dynamic_rows, dynamic_row_width, dynamic_rows);
	int * dynamic_score_buffer = (int *)thread_context -> dynamic_programming_score_buffer;
	char * dynamic_movement_BEFORE_buffer = thread_context -> dynamic_programming_movement_buffer;
	//LRMprintf("SETTING 0 TO %p : %lu bytes\n", dynamic_score_buffer,sizeof(int) * dynamic_row_width * dynamic_rows);
	memset(dynamic_score_buffer, 0, sizeof(int) * dynamic_row_width * dynamic_rows);
	memset(dynamic_movement_BEFORE_buffer, 0, sizeof(char) * dynamic_row_width * dynamic_rows);
	char * indel_movement_buff = (char *) thread_context -> dynamic_programming_indel_movement_buf;
	
	LRMDP_score(0,  trying_indel_length  )=0;
	int read_cursor = last_correct_base, row_i, indel_i;
	unsigned int chro_cursor = last_correct_base_on_chro;

	for(; read_cursor < first_correct_base; read_cursor++){
		row_i = read_cursor - last_correct_base;
		//LRMprintf("Filling Dynamic Matrix : row %d / %d\n", read_cursor, first_correct_base - min(0, expected_indels));
		for(indel_i = dynamic_row_width-1 ; indel_i >=0; indel_i --){ // negative: deletion; positive: insertion
			int testing_indel = indel_i - trying_indel_length;
			if(1){
				int score_from_del = -0x7fffffff, score_from_ins = -0x7fffffff, score_from_match = -0x7fffffff;
				//int is_matched_base = toupper(corrected_read[read_cursor + max(0, testing_indel)]) == toupper(LRMgvindex_get(& context -> current_base_index, chro_cursor - min(0, testing_indel) ));
				int is_matched_base = toupper(corrected_read[read_cursor]) == toupper(LRMgvindex_get(& context -> current_base_index, chro_cursor - testing_indel));

				if(indel_i>0 && row_i>0)
					score_from_ins = LRMDP_score(row_i-1, indel_i-1) + ( (LRMDP_move(row_i-1, indel_i-1) == 'M' || LRMDP_move(row_i-1, indel_i-1) == 'X')?score_create_gap:score_extend_gap);
				if(indel_i < dynamic_row_width-1)
					score_from_del = LRMDP_score(row_i, indel_i+1) + ((LRMDP_move(row_i, indel_i+1) == 'M' || LRMDP_move(row_i, indel_i+1) == 'X')?score_create_gap:score_extend_gap);
				score_from_match =(row_i > 0 ?LRMDP_score(row_i-1, indel_i): 0)+ (is_matched_base?score_match:score_mismatch);
				
				int final_score = max(score_from_del, max(score_from_ins, score_from_match));
				if(testing_indel > 0 && row_i < testing_indel){
					LRMDP_score(row_i, indel_i) = score_create_gap + score_extend_gap  * testing_indel ;
					LRMDP_move(row_i, indel_i) =  'I'; 
				}else{
					LRMDP_score(row_i, indel_i) = final_score;
					LRMDP_move(row_i, indel_i) = score_from_del == final_score?'D':((score_from_ins == final_score)?'I': ( is_matched_base ?'M':'X'));
				}
			}
		}
		chro_cursor ++;
	}

	if(my_debug) LRMindel_dynamic_search_debug(context, dynamic_score_buffer, dynamic_movement_BEFORE_buffer, dynamic_row_width, dynamic_rows, NULL);

	row_i = first_correct_base - last_correct_base - 1;
	indel_i = trying_indel_length + expected_indels;

	moves = 0;
	while(row_i >= 0 && indel_i >=0 && indel_i < dynamic_row_width){
		//#warning "========= DO NOT ASSERT ============="
		indel_movement_buff[moves] = LRMDP_move(row_i, indel_i);
		(* total_mismatched_bases) += (indel_movement_buff[moves]=='X')?1:0;

		if(indel_movement_buff[moves] == 'M' || indel_movement_buff[moves] == 'X') row_i--;
		else if(indel_movement_buff[moves] == 'D') { indel_i++; }
		else {indel_i--; row_i--;}
		moves ++;

		if(row_i < 0 && indel_i < trying_indel_length)
			for(; indel_i < trying_indel_length; indel_i++) indel_movement_buff[moves++] ='D';

		if(moves > max( LRMDYNAMIC_MAXIMUM_GAP_LENGTH * 15, 300 ) +  context -> max_dynamic_indel_length ){
			LRMprintf("ERROR: Dynamic programming moves more than %d\n",  max( (int)(LRMDYNAMIC_MAXIMUM_GAP_LENGTH * 15), 300 ) +  context -> max_dynamic_indel_length);
			return -1;
		}
	}
	
	indel_movement_buff[moves]=0;
	//if(my_debug)LRMprintf("MOVE0 = %s\n", indel_movement_buff);
	for(row_i = 0; row_i < moves/2; row_i++){
		char tmp = indel_movement_buff[row_i];
		indel_movement_buff[row_i] = indel_movement_buff[ moves - row_i - 1];
		indel_movement_buff[ moves - row_i - 1] = tmp;
	}
	if(my_debug)LRMprintf("MOVES = %s\n", indel_movement_buff);

	//#warning "=============== DO NOT EXIT ==========="
	//if(tested ++ > 26) exit(0);
	return moves;
}
	









				
int LRMdonor_score(LRMcontext_t * context, LRMthread_context_t * thread_context, LRMread_iteration_context_t * iteration_context, LRMsegment_mapping_candidate_t * mapping_result, int seg_id, unsigned int secondary_mapping_location, unsigned int secondary_coverage_start , unsigned int secondary_coverage_end, int indel_in_anchor, int indel_in_secondary, int * final_split_point_on_read, int *is_GT_AG_strand, int * final_left_indel_offset){
	LRMgene_value_index_t * value_index = &context->current_base_index;
	int left_indel_offset =  mapping_result -> first_base_position  > secondary_mapping_location? indel_in_secondary : indel_in_anchor ; // may be later calculated from the indel records;
	
	unsigned int gap_on_read_start = mapping_result -> first_base_position  > secondary_mapping_location? secondary_coverage_end : mapping_result -> confident_coverage_end;
	unsigned int gap_on_read_end =  mapping_result -> first_base_position  > secondary_mapping_location? mapping_result -> confident_coverage_start : secondary_coverage_start;

	gap_on_read_start -= 4;
	gap_on_read_end += 4;

	if(gap_on_read_start <= gap_on_read_end){
		
		unsigned int left_virtualHead_abs_offset = min(mapping_result -> first_base_position, secondary_mapping_location);
		unsigned int right_virtualHead_abs_offset = max(mapping_result -> first_base_position, secondary_mapping_location);
		
		// guess_end is the index of the first UNWANTED BASE.
		int most_likely_point = (gap_on_read_start+gap_on_read_end)/2;
		
		// "split_point" is the first base NOT IN piece 1; it is also the first base IN piece 2. 
		int selected_real_split_point = -1, selected_junction_strand = -1;
		char donor_left[3], donor_right[3];
		int best_score = -111111;

		int real_split_point_i;
		int real_split_point_numbers = gap_on_read_end - gap_on_read_start;
		char * read_text = iteration_context -> segment_texts[seg_id];
		int read_len = iteration_context -> segment_lengths[seg_id];
		
		//LRMprintf("START DONOR SEARCH: real_split_point_numbers = %d\n", real_split_point_numbers);
		for(real_split_point_i = 0 ; real_split_point_i < real_split_point_numbers; real_split_point_i++){
			int left_should_match, right_should_match = 0;
			int left_should_not_match = 0, right_should_not_match = 0;
			int real_split_point = (real_split_point_i % 2)?-((real_split_point_i+1)/2):((1+real_split_point_i)/2);
			real_split_point += most_likely_point;
			int is_donor_test_ok = 0;

			if(real_split_point > read_len-JUNCTION_CONFIRM_WINDOW)continue;
			if(real_split_point < JUNCTION_CONFIRM_WINDOW)continue;

			LRMgvindex_get_string (donor_left, value_index, left_virtualHead_abs_offset + real_split_point + left_indel_offset, 2, 0);
			LRMgvindex_get_string (donor_right, value_index, right_virtualHead_abs_offset + real_split_point - 2, 2, 0);
			if(LRMis_donor_chars(donor_left)&& LRMis_donor_chars(donor_right))
				is_donor_test_ok = LRMpaired_chars(donor_left, donor_right);

			int mismatch_in_between_allowd = 1;
			if(is_donor_test_ok){
				left_should_match = LRMmatch_chro(read_text + real_split_point - JUNCTION_CONFIRM_WINDOW, value_index, left_virtualHead_abs_offset + real_split_point - JUNCTION_CONFIRM_WINDOW + left_indel_offset , JUNCTION_CONFIRM_WINDOW , 0);	
				right_should_match = LRMmatch_chro(read_text + real_split_point, value_index, right_virtualHead_abs_offset + real_split_point, JUNCTION_CONFIRM_WINDOW , 0);	

				if(0){
					char pos1txt[100], pos2txt[100];
					LRMpos2txt(context, left_virtualHead_abs_offset + real_split_point + left_indel_offset,  pos1txt);
					LRMpos2txt(context, right_virtualHead_abs_offset + real_split_point + left_indel_offset,  pos2txt);
					LRMprintf("Testing %s ~ %s : GT:AG: %c%c %c%c   OK=%d ; Ml and Mr = %d and %d\n", pos1txt, pos2txt, donor_left[0], donor_left[1], donor_right[0], donor_right[1], is_donor_test_ok, left_should_match, right_should_match);
				}
				if(left_should_match > JUNCTION_CONFIRM_WINDOW- 2){
					
					if(right_should_match >= 2*JUNCTION_CONFIRM_WINDOW - left_should_match - mismatch_in_between_allowd){
						left_should_not_match = LRMmatch_chro(read_text + real_split_point, value_index, left_virtualHead_abs_offset + real_split_point + left_indel_offset, JUNCTION_CONFIRM_WINDOW , 0);	
						right_should_not_match = LRMmatch_chro(read_text + real_split_point - JUNCTION_CONFIRM_WINDOW, value_index, right_virtualHead_abs_offset  + real_split_point - JUNCTION_CONFIRM_WINDOW, JUNCTION_CONFIRM_WINDOW , 0);	

						//LRMprintf("                      Xl and Xr = %d and %d\n", left_should_not_match, right_should_not_match);
						if(left_should_not_match <= JUNCTION_CONFIRM_WINDOW -5 && right_should_not_match <= JUNCTION_CONFIRM_WINDOW -5){
							int test_score ; 
							test_score = 100*(is_donor_test_ok*3000+left_should_match + right_should_match - left_should_not_match - right_should_not_match);

							//LRMprintf("                      BEST REPLACES? %d <?< %d\n", best_score, test_score);
							if(test_score > best_score){
								selected_junction_strand = (donor_left[0]=='G' || donor_right[1]=='G');
								selected_real_split_point = real_split_point;	
								//LRMprintf("                      BEST REPLACESED %d <<- %d\n", best_score, test_score);
								best_score = test_score;
							}
						}
					}
				}
			}
		}
		if(best_score>0)
		{
			*final_split_point_on_read = selected_real_split_point;
			*is_GT_AG_strand = selected_junction_strand;
			*final_left_indel_offset = left_indel_offset;
			return (1+best_score)/100;
		}
	}
	return 0;
}

int LRMevents_search(LRMcontext_t * context, unsigned int testing_pos, int search_for_smaller_coordinate, int * event_ids_buff){
	int * event_here = HashTableGet(context -> events_realignment, NULL + testing_pos);
	if(NULL == event_here)return 0;
	int x1, ret = 0;
	for(x1 = 1; x1< 1+ min(LRMMAX_EVENTS_PER_SITE, event_here[0]); x1++){
		int event_i = event_here[x1] - 1; 
		if(0 > event_i)break;
		
		//LRMprintf("TESTING EVENT AT %u [%d] : %d \n", testing_pos, x1 , event_i);
		LRMevent_t * thise = context -> event_space + event_i;
		if((thise -> large_side ==  testing_pos && !search_for_smaller_coordinate)||
		   (thise -> small_side ==  testing_pos &&  search_for_smaller_coordinate) )
		   event_ids_buff[ret++]=event_i;
	}
	return ret;
}

#define LRMJUMP_TESTING_LEN 16

int LRM_should_jump( LRMcontext_t * context, LRMthread_context_t * thread_context, LRMread_iteration_context_t * iteration_context, LRMrealign_context_t * realign_context, unsigned int other_side_start, int next_seg_pos, LRMevent_t *new_env ){
	int bx1, matched = 0;

	if(new_env -> event_type == LRMEVENT_TYPE_INDEL)return 0;

	if(0){
		LRMprintf("=================\n");
		char poschr[100];
		LRMpos2txt(context, other_side_start, poschr);
		LRMprintf("Match %s and READ + %d to %s end\n", poschr, next_seg_pos,  realign_context -> current_dir_to_3end?"3":"5");

		for(bx1 = 0; bx1 < LRMJUMP_TESTING_LEN; bx1++){
			int testing_read_pos = realign_context -> current_dir_to_3end? next_seg_pos + bx1 :(next_seg_pos - bx1);
			unsigned int testing_chro_pos = realign_context -> current_dir_to_3end? other_side_start + bx1 : (other_side_start - bx1);
			if(testing_read_pos >= iteration_context -> segment_lengths[realign_context -> current_segment_id]) break;
			if(testing_read_pos <0) break;

			char chro_ch = LRMgvindex_get(&context -> current_base_index, testing_chro_pos);
			char read_ch = iteration_context -> segment_texts[ realign_context -> current_segment_id ][testing_read_pos];

			LRMprintf("    %c %c\n", chro_ch, read_ch);
		}
		LRMprintf("=================\n\n");
	}
	int tested_bases = 0;
	for(bx1 = 0; bx1 < LRMJUMP_TESTING_LEN; bx1++){
		int testing_read_pos = realign_context -> current_dir_to_3end? next_seg_pos + bx1 :(next_seg_pos - bx1);
		unsigned int testing_chro_pos = realign_context -> current_dir_to_3end? other_side_start + bx1 : (other_side_start - bx1);
		if(testing_read_pos >= iteration_context -> segment_lengths[realign_context -> current_segment_id]) break;
		if(testing_read_pos <0) break;
		char chro_ch = LRMgvindex_get(&context -> current_base_index, testing_chro_pos);
		char read_ch = iteration_context -> segment_texts[ realign_context -> current_segment_id ][testing_read_pos];
		tested_bases ++;
		matched += (read_ch == chro_ch);
	}

	if(matched<1)return 0;
	return matched >= tested_bases - LRMJUMP_MISMATCH_TOLERANCE;
}

void LRMrealign_one_segment_bestresult( LRMcontext_t * context, LRMthread_context_t * thread_context, LRMread_iteration_context_t * iteration_context, LRMrealign_context_t * realign_context ){
	int current_score = 0;
	int x1;

	for(x1 = 0; x1 < realign_context -> current_stack_depth ; x1++)
		current_score += realign_context -> current_stack_matched_bases[x1];

	//LRMprintf("  TEST SCORE %s : %d > %d ; DEPTH : %d > %d\n", realign_context -> current_dir_to_3end?"AFT":"FWD", current_score, realign_context -> best_stack_score, realign_context -> current_stack_depth, realign_context -> best_stack_depth [realign_context -> current_dir_to_3end] );

	if(realign_context -> best_stack_depth[realign_context -> current_dir_to_3end] < 1 || current_score > realign_context -> best_stack_score [ realign_context -> current_dir_to_3end ] ){
		realign_context -> best_stack_score [realign_context -> current_dir_to_3end] = current_score;
		realign_context -> best_stack_depth[realign_context -> current_dir_to_3end] = realign_context -> current_stack_depth ;
		memcpy(realign_context -> best_stack_segment_length[realign_context -> current_dir_to_3end], realign_context -> current_stack_segment_length, sizeof(int) * realign_context -> current_stack_depth);
		memcpy(realign_context -> best_stack_segment_first_base_position[realign_context -> current_dir_to_3end], realign_context -> current_stack_segment_first_base_position, sizeof(int) * realign_context -> current_stack_depth);
		memcpy(realign_context -> best_stack_event_after[realign_context -> current_dir_to_3end], realign_context -> current_stack_event_after, sizeof(int) * realign_context -> current_stack_depth );
		memcpy(realign_context -> best_stack_chro_first_base_position[realign_context -> current_dir_to_3end], realign_context -> current_stack_chro_first_base_position, sizeof(int) * realign_context -> current_stack_depth );
		memcpy(realign_context -> best_stack_softcliping_length[realign_context -> current_dir_to_3end], realign_context -> current_stack_softcliping_length, sizeof(int) * realign_context -> current_stack_depth );
	}
}


int LRMrealign_one_segment_iterating( LRMcontext_t * context, LRMthread_context_t * thread_context, LRMread_iteration_context_t * iteration_context, LRMrealign_context_t * realign_context){
	unsigned int testing_pos;
	
	int seg_id = realign_context -> current_segment_id;
	testing_pos = realign_context -> current_next_iteration_chro_start;
	int having_mismatches = 0;

	while(1){
		if(realign_context -> current_dir_to_3end && realign_context -> current_testing_segment_location >= iteration_context -> segment_lengths[seg_id]) break;
		if(realign_context -> current_dir_to_3end == 0 && realign_context -> current_testing_segment_location < 0) break;
		
		char chro_base = LRMgvindex_get(&context -> current_base_index , testing_pos);
		char read_base = iteration_context -> segment_texts[ realign_context -> current_segment_id ][ realign_context -> current_testing_segment_location ];
		if(having_mismatches < LRMSOFTCLIPPING_MAX_MISMATCH){
			if(chro_base == read_base){
				having_mismatches = 0;
				realign_context -> current_stack_softcliping_length[ realign_context -> current_stack_depth ] = 0;
			}else{
				if(LRMSOFTCLIPPING_MAX_MISMATCH < 1000 && having_mismatches == 0)realign_context -> current_stack_softcliping_length[ realign_context -> current_stack_depth ] = realign_context -> current_dir_to_3end ? ( iteration_context -> segment_lengths[seg_id] - realign_context -> current_testing_segment_location ): (1+realign_context -> current_testing_segment_location);
				having_mismatches ++;
			}
		}

		if(having_mismatches < LRMSOFTCLIPPING_MAX_MISMATCH){
			int found_events [LRMMAX_EVENTS_PER_SITE];
			int event_i, events_at_here = LRMevents_search(context, testing_pos, realign_context -> current_dir_to_3end, found_events);

			if(0 && events_at_here > 0) {
				char postxt[100];
				LRMpos2txt(context, testing_pos , postxt);
				LRMprintf("Mismatch = %d ; Found %d events at %s ; to 3' = %d ; read pos : %d , read len : %d\n", having_mismatches, events_at_here, postxt, realign_context -> current_dir_to_3end,  realign_context -> current_testing_segment_location , iteration_context -> segment_lengths[seg_id]);
			}

			for(event_i = 0; event_i < events_at_here; event_i++){
				LRMevent_t * tested_event = context -> event_space + found_events[event_i];
				unsigned int other_side_start =  realign_context -> current_dir_to_3end? tested_event -> large_side: tested_event -> small_side;
				int next_seg_pos = realign_context -> current_dir_to_3end? realign_context -> current_testing_segment_location +1:( realign_context -> current_testing_segment_location -1);
				if(tested_event -> indel_length < 0)next_seg_pos += ( realign_context -> current_dir_to_3end?-tested_event -> indel_length:tested_event -> indel_length );
				//LRMprintf("    events #%d type: %d; len: %d ; coor: %u ~ %u\n", found_events[event_i] , tested_event-> event_type, tested_event-> indel_length, tested_event->small_side, tested_event -> large_side);
				if(LRM_should_jump( context, thread_context, iteration_context, realign_context, other_side_start,  next_seg_pos, tested_event)){
					int item_length = abs(realign_context -> current_testing_segment_location - realign_context -> current_stack_segment_first_base_position[ realign_context -> current_stack_depth ]) + 1;
					unsigned int item_start_chro_pos =  realign_context -> current_dir_to_3end? ( testing_pos - item_length ) : testing_pos ;
					int item_start_seg_pos = realign_context -> current_dir_to_3end? (  realign_context -> current_testing_segment_location - item_length ):  realign_context -> current_testing_segment_location ;

					realign_context -> current_stack_segment_length[ realign_context -> current_stack_depth ] = item_length;
					realign_context -> current_stack_matched_bases[ realign_context -> current_stack_depth ] = LRMmatch_chro( iteration_context -> segment_texts[ realign_context -> current_segment_id ] + item_start_seg_pos , &context -> current_base_index, item_start_chro_pos, realign_context -> current_stack_segment_length[ realign_context -> current_stack_depth ], 0);
					realign_context -> current_stack_event_after[ realign_context -> current_stack_depth ] = found_events[event_i];
					realign_context -> current_stack_depth ++;
					realign_context -> current_stack_softcliping_length[ realign_context -> current_stack_depth ] = 0;
					realign_context -> current_stack_chro_first_base_position[ realign_context -> current_stack_depth ] = other_side_start;
					realign_context -> current_stack_segment_first_base_position[ realign_context -> current_stack_depth ] = next_seg_pos;
					realign_context -> current_next_iteration_chro_start = other_side_start;
					realign_context -> current_testing_segment_location = next_seg_pos;
					LRMrealign_one_segment_iterating( context, thread_context, iteration_context, realign_context );

					realign_context -> current_stack_depth --;
				}
			}
		}
		
		if(realign_context -> current_dir_to_3end){
			testing_pos ++;
			realign_context -> current_testing_segment_location ++;
		}else{
			testing_pos --;
			realign_context -> current_testing_segment_location --;
		}
	}

	// testing no-event alignment  
	int item_length = abs(realign_context -> current_testing_segment_location - realign_context -> current_stack_segment_first_base_position[ realign_context -> current_stack_depth ]);
	if( item_length >0) {
		int item_start_seg_pos = realign_context -> current_dir_to_3end? (  realign_context -> current_testing_segment_location - item_length ):  realign_context -> current_testing_segment_location ;
		unsigned int item_start_chro_pos =  realign_context -> current_dir_to_3end? ( testing_pos - item_length ) :  testing_pos;

		realign_context -> current_stack_segment_length[ realign_context -> current_stack_depth ] = item_length;
		realign_context -> current_stack_matched_bases[ realign_context -> current_stack_depth ] = LRMmatch_chro( iteration_context -> segment_texts[ realign_context -> current_segment_id ] + item_start_seg_pos , &context -> current_base_index, item_start_chro_pos, realign_context -> current_stack_segment_length[ realign_context -> current_stack_depth ], 0);

		//LRMprintf("  LAST TEST %s : DEP=%d, LEN=%d, MATCH=%d\n", realign_context -> current_dir_to_3end?"AFT":"FWD", realign_context -> current_stack_depth, item_length, realign_context -> current_stack_matched_bases[ realign_context -> current_stack_depth ]);

		realign_context -> current_stack_depth ++;
		realign_context -> current_stack_event_after[ realign_context -> current_stack_depth ] = 0;
		LRMrealign_one_segment_bestresult(context, thread_context, iteration_context, realign_context);
		realign_context -> current_stack_depth --;
	}
	return 0;
}

int LRMrealign_one_segment_build_cigar(LRMcontext_t * context, LRMthread_context_t * thread_context, LRMread_iteration_context_t * iteration_context, LRMrealign_context_t * realign_context){
	int item_i, all_items = realign_context -> best_stack_depth[0]+realign_context -> best_stack_depth[1] - (realign_context -> best_stack_depth[0] >0? 1:0);
	realign_context -> best_cigar[0] = 0;
	int cigar_len_ptr = 0;
	unsigned int entire_segment_chro_pos = 0;
	for(item_i = 0; item_i < all_items; item_i++){
		int start_on_seg = -1, length_of_seg = -1;
		unsigned int start_on_chro = 0;
		LRMevent_t * event_3end_seg = NULL;
		int softcliping_len_before = 0, softcliping_len_after = 0;
		
		if(item_i < realign_context -> best_stack_depth[0]-1){
			int itemidx = realign_context -> best_stack_depth[0] - item_i - 1;
			length_of_seg = realign_context -> best_stack_segment_length[0][itemidx];
			start_on_seg = realign_context -> best_stack_segment_first_base_position[0][itemidx] - length_of_seg;
			start_on_chro = realign_context -> best_stack_chro_first_base_position[0][itemidx] - length_of_seg + 1;

			if( item_i == 0 )softcliping_len_before =  realign_context -> best_stack_softcliping_length[0][itemidx];
			if( item_i == all_items - 1 )softcliping_len_after =  realign_context -> best_stack_softcliping_length[1][itemidx];
			event_3end_seg = NULL;
			if(item_i < all_items - 1) event_3end_seg = context -> event_space + realign_context -> best_stack_event_after[0][itemidx - 1];
		}else if (item_i == realign_context -> best_stack_depth[0] -1){
			length_of_seg = realign_context -> best_stack_segment_length[0][0] + realign_context -> best_stack_segment_length[1][0];
			start_on_seg = realign_context -> best_stack_segment_first_base_position[0][0] - realign_context -> best_stack_segment_length[0][0];
			start_on_chro = realign_context -> best_stack_chro_first_base_position[0][0] - realign_context -> best_stack_segment_length[0][0] + 1;

			if(0 && realign_context -> current_segment_id == 161){
				char postxt[100];
				LRMpos2txt(context, start_on_chro, postxt);
				LRMprintf("MID_SECTION LEN=%d, START=%s, %d ; B0_0 LEN=%d, B0 DEPTH=%d B0_1 LEN=%d B1_0 LEN=%d \n", length_of_seg, postxt, start_on_seg, realign_context -> best_stack_segment_length[0][0], realign_context -> best_stack_depth[0], realign_context -> best_stack_segment_length[0][1], realign_context -> best_stack_segment_length[1][0]);
			}

			if(item_i == 0)softcliping_len_before =  realign_context -> best_stack_softcliping_length[0][ realign_context -> best_stack_depth[0]-1 ];
			if(item_i == all_items - 1)softcliping_len_after =  realign_context -> best_stack_softcliping_length[1] [0];
			event_3end_seg = NULL;
			if(item_i < all_items - 1) event_3end_seg = context -> event_space + realign_context -> best_stack_event_after[1][0];
		}else{
			int itemidx = item_i - realign_context -> best_stack_depth[0] + (realign_context -> best_stack_depth[0] >0? 1:0);
			length_of_seg = realign_context -> best_stack_segment_length[1][itemidx];
			start_on_seg = realign_context -> best_stack_segment_first_base_position[1][itemidx];
			start_on_chro = realign_context -> best_stack_chro_first_base_position[1][itemidx];

			if( item_i == 0 )softcliping_len_before =  realign_context -> best_stack_softcliping_length[0][itemidx];
			if( item_i == all_items - 1 )softcliping_len_after =  realign_context -> best_stack_softcliping_length[1][itemidx];
			event_3end_seg = NULL;
			if(item_i < all_items - 1) event_3end_seg = context -> event_space + realign_context -> best_stack_event_after[1][itemidx];
		}
		
		if(softcliping_len_before)if(cigar_len_ptr < LRMSEGMENT_CIGAR_SIZE) cigar_len_ptr += snprintf(realign_context -> best_cigar + cigar_len_ptr, LRMSEGMENT_CIGAR_SIZE - cigar_len_ptr, "%dS",softcliping_len_before);
		if(cigar_len_ptr < LRMSEGMENT_CIGAR_SIZE)cigar_len_ptr += snprintf(realign_context -> best_cigar + cigar_len_ptr, LRMSEGMENT_CIGAR_SIZE - cigar_len_ptr, "%dM", length_of_seg - softcliping_len_before - softcliping_len_after);
		if(softcliping_len_after)
			if(cigar_len_ptr < LRMSEGMENT_CIGAR_SIZE)cigar_len_ptr += snprintf(realign_context -> best_cigar + cigar_len_ptr, LRMSEGMENT_CIGAR_SIZE - cigar_len_ptr, "%dS",softcliping_len_after);
		if(event_3end_seg){
			char cigar_op = event_3end_seg -> event_type == LRMEVENT_TYPE_JUNCTION?'N':(event_3end_seg -> indel_length > 0?'D':'I'  );
			int cigar_oplen = event_3end_seg -> event_type == LRMEVENT_TYPE_JUNCTION?(event_3end_seg -> large_side - event_3end_seg -> small_side - 1 ):abs(event_3end_seg -> indel_length);
			if(cigar_len_ptr < LRMSEGMENT_CIGAR_SIZE)cigar_len_ptr += snprintf(realign_context -> best_cigar + cigar_len_ptr, LRMSEGMENT_CIGAR_SIZE - cigar_len_ptr, "%d%c", cigar_oplen, cigar_op);
		}
		if(0 == item_i) entire_segment_chro_pos = start_on_chro;
		if(softcliping_len_after) break;
	}
	
	if(0 &&  entire_segment_chro_pos > 0){
		char postxt[100];
		LRMpos2txt(context, entire_segment_chro_pos, postxt);
		LRMprintf("\nREAD %s [%d]\n=== pos: %s TXT %.*s ===", iteration_context -> read_name, realign_context -> current_segment_id, postxt,  iteration_context -> segment_lengths[realign_context -> current_segment_id], iteration_context -> segment_texts[realign_context -> current_segment_id]);
		LRMprintf("=== CIGAR BUILT : %s ; ITEMS = %d + %d = %d ===\n", realign_context -> best_cigar,  realign_context -> best_stack_depth[0], realign_context -> best_stack_depth[1], all_items);
	}
	
	realign_context -> best_chro_pos = entire_segment_chro_pos;
	return 1;
}

int LRMrealign_one_segment(LRMcontext_t * context, LRMthread_context_t * thread_context, LRMread_iteration_context_t * iteration_context, LRMrealign_context_t * realign_context){
	int read_reversed = 0;
	LRMread_mapping_result_t * read_res = context -> read_mapping_results + iteration_context -> read_no_in_chunk;
	LRMsegment_mapping_result_t * seg_res = read_res -> segment_results + realign_context -> current_segment_id;
	LRMsegment_mapping_candidate_t * cand_res = seg_res -> candidates + realign_context -> current_candidate_id;

	if(context -> do_junction_detection){

			realign_context -> current_dir_to_3end = 0;
			realign_context -> best_stack_score[0] = 0;
			realign_context -> current_stack_depth = 0;
			realign_context -> best_stack_depth[0]=0;
			realign_context -> best_stack_segment_length[0][0]=0;
			
			realign_context -> current_stack_segment_first_base_position[0] = cand_res -> confident_coverage_start - 1;
			realign_context -> current_next_iteration_chro_start = cand_res -> first_base_position + cand_res -> confident_coverage_start - 1;
			realign_context -> current_stack_chro_first_base_position[0] = realign_context -> current_next_iteration_chro_start;
			realign_context -> current_stack_softcliping_length[0] = 0;
			realign_context -> current_testing_segment_location = cand_res -> confident_coverage_start - 1;


			//#warning "======== SHOULD NOT RETURN FOR NEGATIVE STRAND ================"
			//if(cand_res -> masks & LRMIS_NEGATIVE_STRAND) return 0;
			if( (cand_res -> masks & LRMIS_NEGATIVE_STRAND) != (read_reversed?LRMIS_NEGATIVE_STRAND:0)){
				LRMreverse_read(iteration_context -> segment_texts[realign_context -> current_segment_id], iteration_context -> segment_lengths[realign_context -> current_segment_id]);
				//LRMreverse_read(iteration_context -> read_text, iteration_context -> read_length);
				read_reversed = !read_reversed;
			}

			if(0 &&  realign_context -> current_segment_id == 13){
				char postxt[100];
				LRMpos2txt(context, cand_res -> first_base_position + cand_res -> confident_coverage_start , postxt);
				int ccc = iteration_context -> segment_texts[realign_context -> current_segment_id][iteration_context -> segment_lengths[realign_context -> current_segment_id]];
				iteration_context -> segment_texts[realign_context -> current_segment_id][iteration_context -> segment_lengths[realign_context -> current_segment_id]] = 0;
				LRMprintf("\nREALIGN SEG %d (%s): FROM %s MASKS=%u  CONF_START=%d\n%s\n\n", realign_context -> current_segment_id, (cand_res -> masks & LRMIS_NEGATIVE_STRAND)?"NEG":"POS", postxt , cand_res -> masks, cand_res -> confident_coverage_start, iteration_context -> segment_texts[realign_context -> current_segment_id]);
				iteration_context -> segment_texts[realign_context -> current_segment_id][iteration_context -> segment_lengths[realign_context -> current_segment_id]] = ccc;
			}

			//LRMprintf("REAL %s SEG %d MASK %d REV %d [%dbp] at %p : %.*s\n", iteration_context -> read_name,  realign_context -> current_segment_id, cand_res -> masks, read_reversed, iteration_context -> segment_lengths[realign_context -> current_segment_id], iteration_context -> segment_texts[realign_context -> current_segment_id],  iteration_context -> segment_lengths[realign_context -> current_segment_id], iteration_context -> segment_texts[realign_context -> current_segment_id]);
				
			LRMrealign_one_segment_iterating(context, thread_context, iteration_context, realign_context);

			if(0 && realign_context -> current_segment_id == 13){
				char postxt[100];
				LRMpos2txt(context,  realign_context -> best_stack_chro_first_base_position [0][realign_context -> best_stack_depth[0]-1] - realign_context -> best_stack_segment_length[0][ realign_context -> best_stack_depth[0]-1 ],  postxt);
				LRMprintf("REALIGN_FWD_RES : SCORE=%d, ITEMS=%d ; ITEMS_FIRST BASE: %s ; ITEMS_FIRST LEN : %d\n", realign_context -> best_stack_score [0], realign_context -> best_stack_depth[0],  postxt, realign_context -> best_stack_segment_length[0][ realign_context -> best_stack_depth[0]-1 ]);
			}

			realign_context -> current_dir_to_3end = 1;
			realign_context -> best_stack_score[1] = 0;
			realign_context -> current_stack_depth = 0;
			realign_context -> best_stack_depth[1]=0;
			realign_context -> best_stack_segment_length[1][0]=0;

			realign_context -> current_stack_segment_first_base_position[0] = cand_res -> confident_coverage_start;
			realign_context -> current_next_iteration_chro_start = cand_res -> first_base_position + cand_res -> confident_coverage_start;
			realign_context -> current_stack_chro_first_base_position[0] = realign_context -> current_next_iteration_chro_start;
			realign_context -> current_stack_softcliping_length[0] = 0;
			realign_context -> current_testing_segment_location = cand_res -> confident_coverage_start;
			
			LRMrealign_one_segment_iterating(context, thread_context, iteration_context, realign_context);
			if(0 && realign_context -> current_segment_id == 13){
				LRMprintf("REALIGN_AFT_RES : SCORE=%d, ITEMS=%d\n", realign_context -> best_stack_score [realign_context -> current_dir_to_3end], realign_context -> best_stack_depth[realign_context -> current_dir_to_3end]);
			}
			
			LRMrealign_one_segment_build_cigar(context, thread_context, iteration_context, realign_context);

			if(0 && realign_context -> current_segment_id == 13) LRMprintf("REALIGN_CIGAR: %s\n",realign_context -> best_cigar);

			if(read_reversed){
				LRMreverse_read(iteration_context -> segment_texts[realign_context -> current_segment_id], iteration_context -> segment_lengths[realign_context -> current_segment_id]);
			//	LRMreverse_read(iteration_context -> read_text, iteration_context -> read_length);
			}
	}else{
		int skip_head = 0, skip_tail = 0;
		skip_head = (cand_res -> confident_coverage_start + cand_res -> confident_coverage_end)/2;
		skip_tail = iteration_context -> segment_lengths[realign_context -> current_segment_id] - 1 - skip_head;
		sprintf(realign_context -> best_cigar, "%dS1M%dS", skip_head, skip_tail);
		realign_context -> best_chro_pos = cand_res -> first_base_position;
		realign_context -> best_stack_score[0] = cand_res -> votes; 
		realign_context -> best_stack_score[1] = cand_res -> votes; 
	}
	return 0;
}
