(function(exports){
	'use strict'
	
	
	// Контрольная сумма данных
	function checksum(data)
	{
		return data.reduce( function(A,V) { return (A+V) & 0xff; } );
	}
	
	
	// Перевод в hex
	var hex_digits="0123456789ABCDEF";
	function hex(v)
	{
		return hex_digits[(v >> 4) & 0x0f] + hex_digits[v & 0x0f];
	}
	
	
	// Прочитать файл
	exports.load = function(filename, sections) {
		
		// Создаем пустые данные
		sections.forEach(
			function(section)
			{
				section.data=[];
			} );
		
		// Читаем и парсим файл
		var segment=0;
		fs.read(filename)
			.replace(/\r/g, '')
			.split('\n')
			.forEach(
				function(text)
				{
					// Пропускаем пустые строки
					if (text.length == 0) return;
					
					// Проверим префикс и длину строки
					if ( (text[0] != ':') || ((text.length & 1) == 0) ) throw new Error("incorrect file format '"+text+"'");
					
					function unhex(c)
					{
						c=c.charCodeAt(0);
						
						if ( (c>=0x30) && (c<=0x39) ) return c-0x30; else
						if ( (c>=0x41) && (c<=0x46) ) return c-0x41+10; else
						if ( (c>=0x61) && (c<=0x66) ) return c-0x61+10; else
							throw new Error("incorrect hex digit '"+c+"'");
					}
					
					// Разбираем строку
					var data=[];
					for (var i=0; i<(text.length-1)/2; i++)
					{
						data[i]=(unhex(text[1+i*2+0]) << 4) | unhex(text[1+i*2+1]);
					}
					
					// Проверяем контрольку и удаляем ее из данных
					if (checksum(data) != 0x00) throw new Error("checksum error");
					data.pop();
					
					// Проверяем длину данных
					if (data[0]+4 != data.length) throw new Error("bad length field");
					
					// Получаем адрес
					var address=(data[1] << 8) | data[2];
					
					// Проверяем тип записи
					switch (data[3])
					{
						case 0:
							// Данные
							sections.forEach(
								function(section)
								{
									if ( (segment+address >= section.address) &&
										 (segment+address < section.address+section.size) )
									{
										// Входит в сегмент
										for (var i=0; i<data[0]; i++)
											section.data[segment+address+i - section.address] = data[4+i];
									}
								} );
							break;
						
						case 1:
							// Конец файла - пропускаем
							break;
						
						case 2:
							// Адрес сегмента
							segment=0;
							for (var i=0; i<data[0]; i++)
							{
								segment<<=8;
								segment |= data[4+i];
							}
							segment<<=4;
							break;
						
						case 3:
							// Адрес старта - пропускаем
							break;
						
						case 4:
							// Линейный адрес
							segment=0;
							for (var i=0; i<data[0]; i++)
							{
								segment<<=8;
								segment |= data[4+i];
							}
							segment<<=16;
							break;
						
						case 5:
							// Адрес старта - пропускаем
							break;
						
						default:
							throw new Error("incorrect field type "+data[3]);
					}
				} );
		
		return sections;
		
	};
	
	
	// Записать файл
	exports.save = function(filename, sections) {
		var MAX_SIZE = 32;
		var lines=[];
		var segment=0;
		
		function putLine(data)
		{
			// Добавляем контрольку
			data.push((0x100 - checksum(data)) & 0xff);
			
			// Создаем строку
			var text=":";
			for (var i=0; i<data.length; i++)
				text+=hex(data[i]);
			
			lines.push(text);
		}
		
		// Сохраняем все секции
		sections.forEach(
			function(section)
			{
				for (var offs=0; offs<section.data.length; offs+=MAX_SIZE)
				{
					// Вставим запись адреса, если надо
					if (((section.address+offs) >> 16) != segment)
					{
						segment=(section.address+offs) >> 16;
						putLine( [ 0x02, 0x00, 0x00, 0x04, (segment >> 8) & 0xff, segment & 0xff ] );
					}
					
					// Получаем длину блока
					var l=section.data.length - offs;
					if (l > MAX_SIZE) l=MAX_SIZE;
					
					// Создаем блок данных
					var A=(section.address+offs) & 0xffff;
					var data=[ l, (A >> 8) & 0xff, A & 0xff, 0x00 ];
					var empty=true;
					for (var i=0; i<l; i++)
					{
						var b=section.data[offs + i]
						if (b !== undefined) empty=false;
						data.push(b);
					}
					if (! empty) putLine(data);
				}
			} );
		
		// Добавляем конец данных
		putLine( [ 0x00, 0x00, 0x00, 0x01 ] );
		lines.push("");
		
		// Сохраняем в файл
		fs.write(filename, lines.join("\r\n"));
	};
	
})(typeof exports === 'undefined' ? this['_IntelHex_js']={} : exports);
