var ALL_COUNT=0;
var MAX_COUNT=400000;
var l_start;
var g_path;
var route_arr = new Array();
var path_array = new Array();
var map;
var directions;
var g_bad_route=0;
var full_c=0;
var distance_matrix = new Array();
var g_row, g_col;
var g_action, g_optimal;
var geocoder;
var g_cur_point;
var min_route_arr = new Array();
var g_current_route;
var path_directions = new Array();
var line = new GPolyline();
var	path_directions0=new GDirections();
var	path_directions1=new GDirections();
var	path_directions2=new GDirections();
var color_arr = [['#00bb00','зеленый'],['#ff6600','оранжевый'],['#ff0000','красный']];
var test_arr = new Array();
var test_dir;
var path_details = new Array();
var	g_bound;

var baseIcon = new GIcon(G_DEFAULT_ICON);
baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
baseIcon.iconSize = new GSize(20, 34);
baseIcon.shadowSize = new GSize(37, 34);
baseIcon.iconAnchor = new GPoint(9, 34);
baseIcon.infoWindowAnchor = new GPoint(9, 2);

function start_routing(p_optimal)
	{
	clear();
	g_optimal=p_optimal;
	check_addr(1);
	}

function check_addr(p_no)
	{
	var l_no=p_no;
	var obj = new Object();
	geocoder = new GClientGeocoder();
	while (obj=document.getElementById('route_point'+l_no))
		{
		if (obj.value.length<5)
			{
			//пустой адрес
			obj.style.background='#ffcccc';
			if (!remove_route_point(obj)) l_no++
			else if (!document.getElementById('route_point'+l_no))
				{
				get_route();
				}
			}
		else
			{
			geocoder.getLocations(obj.value, function(responce) {check_responce(responce, l_no);});
			return;
			}
		}
	alerts.innerHTML='Уточните адреса подсвеченных пунктов маршрута!';
	}

function check_responce(responce, p_no)
	{
	var txt='';
	var c;
	var obj = new Object();
	if (responce.Placemark)
		{
		if (responce.Placemark.length>1)
			{
			txt='';
			for (c=0;c<responce.Placemark.length;c++)
				txt+='<a id="addr_sel'+c+'" href="Javascript:void(0);" onClick="sel_addr(this);" style="font-size: 10px; padding-left:0px; margin-left:0px;">'+responce.Placemark[c].address+'</a><br>';
			obj=document.getElementById("route_point"+p_no);
			obj.style.background='#ffcccc';
			g_bad_route++;
			obj.point=null;
			obj=document.getElementById("div"+p_no);
			obj.innerHTML=txt;
			obj.style.display='block';
			obj.className='dropdown';
			}
		else if (responce.Placemark.length==1)
			{
			var l_addr=responce.Placemark[0].address;
			if (l_addr.search('город')>0) 
				{
				l_addr=l_addr.substr(l_addr.search('город')+6);
				}
			obj=document.getElementById("route_point"+p_no);
			obj.value=l_addr;
			obj.point=responce.Placemark[0].Point.coordinates;
			obj.style.background='#ffffff';
			}
		}
	else 
		{
		obj=document.getElementById('route_point'+p_no);
		obj.style.background='#ffcccc';
		g_bad_route++;
		}

	if (obj=document.getElementById("route_point"+(Number(p_no)+1)))
		check_addr(Number(p_no)+1);
	else if (g_bad_route>0)
		{
		// Есть ошибки в точках маршрута
		alerts.innerHTML='Уточните адреса подсвеченных пунктов маршрута!';
		}
	else get_route();
	}
	
function sel_addr(p_obj)
	{
	var d_obj=p_obj.parentNode;
	var obj=document.getElementById("route_point"+d_obj.id.substr(3));
	obj.value=p_obj.innerText;
	if (obj.value.search('город')>0) 
		{
		obj.value=obj.value.substr(obj.value.search('город')+6);
		}
	obj.style.background='#ffffff';
	d_obj.style.display='none';
	}

function get_route()
	{
		var ext=false;
		var err_txt='';
		process_bar(0);
		// инициализируем начальные условия
		init();
		if (g_bad_route>0) {err_txt='Уточните адреса подсвеченных пунктов маршрута!<br>'; ext=true;}
		if (g_path.length<2) {err_txt+='Укажите не менее двух пунктов маршрута!'; ext=true;}
		if (ext) {alerts.innerHTML=err_txt; return;}
		ALL_COUNT=0;
		// если в адресах ошибок нет, то создаем матрицу расстояний
		create_matrix();
	}

function process_bar(p_val)
	{
	if ((p_val<=1) || (p_val==100)) alerts.innerHTML="Идет обработка, "+p_val+"% завершено...";
	else alerts.innerHTML="Идет обработка, "+Math.round(100*(p_val)/(g_path.length*g_path.length))+"% завершено...";
	}

function init()
   {
	var obj = new Object();
	var cur=1;
	while (obj=document.all["route_point"+cur])
		  {
		  if (obj.value=='') 
			{if (!remove_route_point(obj)) cur++;}
		  else if (((obj.value.length<10) && (obj.value!='')) || (obj.style.background=="#ffcccc")) {obj.style.background="#ffcccc"; cur++; g_bad_route++; }
		  else if (obj.value!='') {g_path.push(cur); cur++; obj.style.background="#ffffff";}
		  }
		route_arr[0]=[g_path,-1];
		if (g_optimal) {
			alerts.innerText='Построение матрицы путей...';
			step();
			}
	}
	
function clear()
	{
		ALL_COUNT=0;
		g_bad_route=0;
		g_cur_point=1;
		g_action='start';
		g_bound = new GLatLngBounds();
		g_path = new Array();
		route_arr = new Array();
		path_arr = new Array();
		min_route_arr = new Array();
		path_details = new Array();
		full_c=0;
		map=new GMap2(document.getElementById("map_canvas"));
		map.setCenter(new GLatLng(55.755713,37.617874), 10);
		directionsPanel = document.getElementById("final_route_details");
		final_route_map = new GDirections(map, directionsPanel);
		directions = new GDirections();
		map.addControl(new GLargeMapControl3D());
		map.addControl(new GMapTypeControl());
		GEvent.addListener(directions, "load", on_directions_load);
		GEvent.addListener(final_route_map, "load", on_final_route_map_load);
		GEvent.addListener(directions, "error", on_map_error);
		final_route.innerHTML="";
		final_route_details.innerHTML='';
		final_route_details.style.display="none";
		alerts.innerHTML="";
	}

function create_matrix()
	{
	g_action='matrix';
	distance_matrix = new Array();
	var col, row;
	for (row=1;row<=g_path.length;row++) 
	  {
		distance_matrix[row] = new Array();
		for (col=1;col<=g_path.length;col++)
			{
			distance_matrix[row][col] = new Array();
			// для плечей 1-1, 2-2,... (диагональ матрицы, длина пути не имеет смысла) запрещаем запрос длины пути 	
			if ((col==row) || (col==1)) distance_matrix[row][col][0]=-2
			// если строим маршрут "как есть", то заполняем только линейный путь (1-2-3-4-5...)	
			else if ((!g_optimal) && (col!=(Number(row)+1))) distance_matrix[row][col][0]=-2
			else distance_matrix[row][col][0]=-1;
			distance_matrix[row][col][1]=null;//polyline
			}
	  }
	process_bar(1);  
	loading_matrix();
	}
	
function loading_matrix()
	{// загружаем матрицу расстояний, просчитывая пары точек
	var col, row;
	for (row in distance_matrix)
		{
		for (col in distance_matrix[row])
			{
			if ((distance_matrix[row][col][0]>-2) && (distance_matrix[row][col][0]<0))
					{// если индексы матрицы не совпадают (!=-2) и текущая длина еще не установлена (=-1), то определяем маршрут и выходим
					process_bar((Number(row)-1)*g_path.length+Number(col));
					path_array= new Array();
					path_array[0]=eval("route_point"+row+".value");
					path_array[1]=eval("route_point"+col+".value");
					g_row=row;
					g_col=col;
					ALL_COUNT++;
					directions.clear();
					if (route_arr.length > 3) pause(50);
					directions.loadFromWaypoints(path_array, {getPolyline: true});
					return;
					}
			}
		}
	//если не вышли, значит все определили и можно продолжать обработку		
//	debug_show_matrix();
	process_bar(100);
	process_route();
	}

function process_route()
	{
	var c;
	var l_p1,l_p2,l_pos;
	for (c in route_arr)
	  {
	  if (route_arr[c][1]<0) 
		{
		l_pos=0;
		route_arr[c][1]=0;
		route_arr[c][2] = [null];
		while (l_pos<route_arr[c][0].length-1)
			{
			l_p1=route_arr[c][0][l_pos];
			l_p2=route_arr[c][0][l_pos+1];
			route_arr[c][1]=route_arr[c][1]+distance_matrix[l_p1][l_p2][0];
			route_arr[c][2].push(distance_matrix[l_p1][l_p2][0]);
			l_pos++;
			}
		}
	  }
	route_arr.sort(get_min)	;
		c=0;
		var txt='';
		alerts1.innerHTML='';
		path_array=new Array();
		while ((c<route_arr.length) && (c<3))
			{
			get_path_array(c);
			c++;
			}
		alerts1.innerHTML=txt;
	get_final_route();
	}	

function get_min(a,b)
	{
	return a[1]-b[1];
	}
	
function get_path_array(p_arr_id)
	{
	var c=0;
	var ch;
	path_array[p_arr_id] = new Array();
	while (c<route_arr[p_arr_id][0].length)
		{
		ch=route_arr[p_arr_id][0][c];
		path_array[p_arr_id][c]=eval("route_point"+ch+".value");
		c++;
		}
	}

function on_directions_load()
	{
	if (g_action=='matrix')
		{
		distance_matrix[g_row][g_col][0]=directions.getDistance().meters;
		distance_matrix[g_row][g_col][1]=directions.getPolyline();
		if ((g_row<g_path.length) || (g_col<g_path.length))
			{
			// если последнюю ячейку матрицы еще не обработали, то обрабатываем матрицу дальше
			loading_matrix();
			}
		else
			{
			//если последнюю ячейку матрицы обработали, то оптимизируем маршрут
			// сюда мы, по идее, не должны попадать никогда... а дальнейшая обработка - в loading_matrix
			//alert('waypoints_loaded='+ALL_COUNT+'\n lets optimize this!');
			alert('Ошибка выполнения скрипта: код waypts_loaded');
			}
		}
	else if (g_action=='start')
		{
		// это мы проверяем правильность адресов
		//alert('addr check');
		alert('Ошибка выполнения скрипта: код addr_check');
		}
	}

function get_final_route()
	{
	alerts.innerHTML='Получение данных маршрута...'
	path_directions = new Array();
	var txt='';
	for (c in path_array)
		{
		txt+='<tr><td id="path'+c+'"></td></tr>';
		
		path_details[c] = new Object();
		path_details[c].line=null;
		path_details[c].markers=null;
		path_details[c].dist=null;
		var line_arr = new Array();
		var marker_arr = new Array();
		  for (pt in route_arr[c][0])
			{
			var obj=new Object();
			obj=document.getElementById('route_point'+route_arr[c][0][pt]);
			var l_point = new GLatLng(obj.point[1],obj.point[0]);
			g_bound.extend(l_point);
			var l_icon=new GIcon(baseIcon);
			l_icon.image = 'http://maps.gstatic.com/intl/ru_ALL/mapfiles/marker_green'+get_char(pt)+'.png';
			var l_marker= new GMarker(l_point, {icon: l_icon, title: obj.value});
			marker_arr.push(l_marker);
				
				if (distance_matrix[route_arr[c][0][Number(pt)]][route_arr[c][0][Number(pt)+1]])
					{
					l_line= new Object();
					l_line=distance_matrix[route_arr[c][0][Number(pt)]][route_arr[c][0][Number(pt)+1]][1]
					line_arr.push(l_line);
					}
			
			}
		path_details[c].line=line_arr;
		path_details[c].markers=marker_arr;
		}
		
	final_route.innerHTML='<span class=h1>Построенные маршруты</span><br><br><table class=finalroute  valign=top>'+txt+'</table>';
    on_path_directions_load();
	
	}

function getLegTime(p_m)
	{
	if (!p_m) return('---');
	return((p_m/1000).toFixed(1)+' км (около '+Math.round(((p_m/1000)/28*60))+' мин. в пути)');
	}
	
function get_path_array_info(p_id)
	{
    var l_text='';
	for (cur in path_array[p_id])
			{
			if (l_text=='') l_text="<tr><td>Пункт А (старт)</td><td>"+path_array[p_id][cur]+"</td><td>---</td></tr>"
			else l_text=l_text+"<tr><td>Пункт "+get_char(cur)+"</td><td>"+path_array[p_id][cur]+"</td><td>"+getLegTime(route_arr[p_id][2][cur])+"</td></tr>";
			}
	l_text='<font style="font-size: 14px; color: '+color_arr[p_id][0]+'"><a href="javascript:void(0);" title="Нажмите, чтобы отобразить маршрут на карте" class=innerlink onClick="showPath('+p_id+');">Маршрут '+(Number(p_id)+1)+'</a>: '+getLegTime(route_arr[p_id][1])+'</font><br><br>'
		+'<table  cellpadding=5 cellspacing=0 valign="top" border=1 style="font-size: 14px;">'
		+'<tr><td>Пункт маршрута</td><td>Адрес</td><td>Расстояние до предыдущей точки</td></tr>'+l_text
		+'</td></tr></table><br>';
	return(l_text);	
	}

function on_path_directions_load()
	{
		alerts.innerHTML='Маршрут построен.';
		for (c in path_array)
			{
			var obj= new Object();
			if (obj=document.getElementById("path"+c))
				obj.innerHTML=get_path_array_info(c);
			}
		showPath(0);
	
	}
	
function showPath(p_id)
	{
	map.clearOverlays();
	for (c in path_details[p_id].markers)
		{
			map.addOverlay(path_details[p_id].markers[c]);
		}
	for (c in path_details[p_id].line)
		{
		var l_line= new Object();
		l_line = path_details[p_id].line[c];
		l_line.color=color_arr[p_id][0];
		l_line.opacity=1;
		map.addOverlay(l_line);
		}
	map.setCenter(g_bound.getCenter(),map.getBoundsZoomLevel(g_bound));
	}
	
	
function debug_show_matrix()
	{
	var txt='';
	var col, row;
	for (row in distance_matrix)
		{
		txt=txt+'<tr>';
		for (col in distance_matrix[row])
			txt=txt+'<td>'+distance_matrix[row][col][0]+'</td>';
		txt=txt+'</tr>';
		}
		
	alerts1.innerHTML='<table>'+txt+'</table>';	
	}

function step(p_path,p_base)
	{
	if (!p_base) 
		{
		p_base = new Array();
		p_path = new Array();
		p_base.push(1);
		for (c in g_path) p_path.push(g_path[c]);
		p_path.shift();
		}
	
	if (p_path.length>1)
		{

		// база для рекурсии
		var l_base1 = new Array();
		for (c in p_base) l_base1.push(p_base[c]);
		// путь для рекурсии
		var l_path2 = new Array();
		for (c in p_path) l_path2.push(p_path[c]);
		l_base1.push(l_path2.shift());
		step(l_path2,l_base1);
		}

	//массив для сдвига в цикле
	var l_path = new Array(); 
	for (c in p_path) l_path.push(p_path[c]);
	//база для цикла
	var l_base=new Array();
	for (c in p_base) l_base[c]=p_base[c];
	
	var i=1;	
	while ((p_path.length>i) && (ALL_COUNT<MAX_COUNT))
		{
		l_path.push(l_path.shift());
		//массив для сохранения
		var l_path1=new Array();
		for (c in p_base) l_path1.push(p_base[c]);
		for (c in l_path) l_path1.push(l_path[c]);
		route_arr.push([l_path1,-1]);
		// база для рекурсии
		var l_base1 = new Array();
		for (c in l_base) l_base1.push(l_base[c]);
		// путь для рекурсии
		var l_path2 = new Array();
		for (c in l_path) l_path2.push(l_path[c]);
		l_base1.push(l_path2.shift());
		i++;
		ALL_COUNT++;
		if (ALL_COUNT>=MAX_COUNT) {alert('Переполнение комбинатора.'); return;}
		step(l_path2,l_base1);
		}
	}
	
function on_final_route_map_load()
	{
		final_route.innerHTML=get_path_array_info(0);
		alerts.innerHTML="Обработка завершена.";
	}

function get_char(p_pos)
	{
	var alf = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
	return(alf.substr(p_pos,1));
	}
	
function on_map_error()
    {
     if (directions.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
         alerts.innerHTML='Невозможно определить местоположение указанного адреса. Возможно адрес указан неверно!<br>Код ошибки карт:'+ directions.getStatus().code
       else if (directions.getStatus().code == G_GEO_SERVER_ERROR)
         alerts.innerHTML='Невозможно определить местоположение указанного адреса. Неизвестная ошибка.<br>Код ошибки карт:'+ directions.getStatus().code
       else if (directions.getStatus().code == G_GEO_MISSING_QUERY)
         alerts.innerHTML='Невозможно определить местоположение указанного адреса. Указан пустой адрес!<br>Код ошибки карт:'+ directions.getStatus().code
       else if (directions.getStatus().code == G_GEO_BAD_KEY)
         alerts.innerHTML='Указанный ключ карт не принадлежит этому домену!<br>Код ошибки карт:'+ directions.getStatus().code
       else if (directions.getStatus().code == G_GEO_BAD_REQUEST)
         alerts.innerHTML='Невозможно обработать (разобрать) указанный маршрут!<br>Код ошибки карт:'+ directions.getStatus().code
       else alerts.innerHTML='Во время выполнения произошла неизвестная ошибка. Возможно не удается построить указанный маршрут.';
    }

function remove_route_point(p_obj)
	{
    
	var l_id=p_obj.id;
	var obj = new Object();
	var obj1 = new Object();
	var num='';
	var cur=1;
	var pr_remove=false;
	var empty_c=0;
	var full_c=0;
	var on,nn;
	if (l_id.substr(0,2)=='dl') l_id="route_point"+l_id.substr(2);
	while (obj=document.all["route_point"+cur])
		{
		if (obj.value=='') empty_c++
		else full_c++;
		cur++;
		}
	cur=1;
	while (obj=document.all["route_point"+cur])
		{
		if (num!='') 
			{
			on=obj.id.substr(11)
			nn=on-1;
			obj.id="route_point"+nn;
			document.getElementById("up"+on).id="up"+nn;
			document.getElementById("dn"+on).id="dn"+nn;
			document.getElementById("dl"+on).id="dl"+nn;
			document.getElementById("div"+on).id="div"+nn;
			}
		if ((obj.id==l_id) && (num==''))
			if ((full_c+empty_c)>2)
				{
				num=obj.id.substr(11); 
				obj.outerHTML=''; 
				if (obj1=document.getElementById("up"+num)) obj1.outerHTML='';
				if (obj1=document.getElementById("dn"+num)) obj1.outerHTML='';
				if (obj1=document.getElementById("dl"+num)) obj1.outerHTML='';
				if (obj1=document.getElementById("div"+num)) obj1.outerHTML='';
				pr_remove=true;}
			else
				{
				obj.value="";
				if (obj1=document.getElementById("div"+obj.id.substr(11))) obj1.style.display='none';
				}
		cur++;
		}
	return(pr_remove);	
	}

function add_route_point(p_txt)
	{
	var obj = new Object();
	var cur=1;
	if (!p_txt) p_txt='';
	while (obj=document.all["route_point"+cur])
		{
		cur++;
		}
	if (cur>10) return(false);
    var new_p = document.createElement("input");
	new_p.id="route_point"+cur;
	new_p.type="text";
	new_p.size="52";
	new_p.value=p_txt;
	route_points.appendChild(new_p);
    var new_p = document.createElement("a");
	new_p.id="up"+cur;
	new_p.innerHTML='<img src="/route2/up.png" alt="Переместить вверх" height="16px" border=0>';
	new_p.onclick=function() {move_point("up",this); return false;}
	new_p.href="Javascript:void(0);";
	new_p.title="Переместить вверх";
	route_points.appendChild(new_p);
    var new_p = document.createElement("a");
	new_p.id="dn"+cur;
	new_p.innerHTML='<img src="/route2/down.png" alt="Переместить вниз" height="16px" border=0>';
	new_p.onclick=function() {move_point("dn",this); return false;}
	new_p.href="Javascript:void(0);";
	new_p.title="Переместить вниз";
	route_points.appendChild(new_p);
    var new_p = document.createElement("a");
	new_p.id="dl"+cur;
	new_p.innerHTML='<img src="/route2/del.png" alt="Удалить пункт" height="16px" border=0>';
	new_p.onclick=function() {if (confirm('Удалить пункт маршрута?')){remove_route_point(this);} return false;}
	new_p.href="Javascript:void(0);";
	new_p.title="Удалить пункт";
	route_points.appendChild(new_p);
    var new_p = document.createElement("div");
	new_p.id="div"+cur;
	new_p.style.width='390px';
	new_p.style.paddingLeft='10px';
	new_p.style.display='none';
	new_p.innerHTML='';
	route_points.appendChild(new_p);
	return(true);
	}	

function move_point(p_dir,p_obj)
	{
	var rp1, rp2 = new Object();
	var tmp, l_no, l_no1, tmp1;
	l_no=p_obj.id.substr(2);
	if (p_dir=='up') l_no1=l_no--
	else l_no1=l_no++;
	if ((rp1=document.getElementById("route_point"+l_no)) && (rp2=document.getElementById("route_point"+l_no1)))
		{
		tmp=rp1.value;
		tmp1=rp1.style.background;
		rp1.value=rp2.value;
		rp2.value=tmp;
		rp1.style.background=rp2.style.background;
		rp2.style.background=tmp1;
		}	
	if ((rp1=document.getElementById("div"+l_no)) && (rp2=document.getElementById("div"+l_no1)))
		{
		tmp=rp1.innerHTML; 
		tmp1=rp1.style.display;
		rp1.innerHTML=rp2.innerHTML;
		rp1.style.display=rp2.style.display;
		rp2.innerHTML=tmp;
		rp2.style.display=tmp1;
		}	
	}

function pause(ms)
{
var date = new Date();
var curDate = null;
do { curDate = new Date(); }
while(curDate-date < ms);
}

function clear_route_points()
	{
	if (!confirm('Удалить все пункты маршрута?')) return false;
	var cur=1;
	var obj = new Object();
	while (obj=document.all["route_point"+cur])
		{
		obj.value='';
		if (obj=document.getElementById("div"+cur)) 
			{
			obj.innerHTML='';
			obj.style.display='none';
			}
		cur++;
		}
	clear();	
	}

function parse_adr()
   {
     var s = String();
	 var r_id=1;
	 var obj = new Object();
     s = document.getElementById('route_text').value;
     r=Array();
     nr = s.split("\n");
     j=0;
     for (i=0;i<nr.length;i++)
      {
       if (nr[i].length>6)/*короткие адреса заведомо неверные - игнорируем*/
        {
		 if (obj=document.getElementById('route_point'+r_id))
			{
			obj.value=nr[i];
			r_id++;
			}
		 else if (add_route_point(nr[i])) r_id++;	
         j++
        }
      }
   }
	

function ShowBlock(pel,plink)
 {
  el = document.getElementById(pel);
  lnk = document.getElementById(plink)
  if (el.style.display=='none') 
   {
    el.style.display='block';
	lnk.innerText = 'скрыть';
   }
 }
function HideBlock(pel,plink)
 {
  el = document.getElementById(pel);
  lnk = document.getElementById(plink)
  if (el.style.display=='block') 
   {
    el.style.display='none';
	lnk.innerText = 'показать';
   }
 }
 
function HideShowBlock(pel,plink)
 {
  el = document.getElementById(pel);
  if (el.style.display=='none') 
   { ShowBlock(pel,plink); }	
  else
   {HideBlock(pel,plink) }
 }
