function EditZeissTiles( filepath, saveas );
if nargin < 1 
	filepath = 'Location of Tiles.czsh File for a ZEISS microscope';
end
[ path, fname, ext ] = fileparts( filepath );
if nargin < 2
	saveas = fullfile( path, [ fname '_edit' ext ] );
end

um_per_px_real = 65;	% physical pixel width/height = 65 um
um_per_px_camera = um_per_px_real / 10;	% 10X magnification at the camera adapter
framew = 2048;	% camera pixel width = 2048 px
frameh = 2048;	% camera pixel height = 2048 px
objmag = 10;	% default objective magnification = 10X

global distw disth
distw = 1;
disth = 1;

tempw = round( input( 'Frame Width (in px) ? ' ) );
temph = round( input( 'Frame Height (in px) ? ' ) );
if ( ~isempty(tempw) && ~isempty(temph) && tempw > 0 && temph > 0 )
	framew = tempw;
	frameh = temph;

	temp = input( 'Objective Magnification ? ' );
	if ( ~isempty(temp) && temp > 0 )
		objmag = temp;
	end

	distw = framew * ( um_per_px_camera / objmag );
	disth = frameh * ( um_per_px_camera / objmag );
end

xDoc = xmlread( filepath );
xIsOptimizedTravelMovement = xDoc.getElementsByTagName('IsOptimizedTravelMovement');
for i = 1:xIsOptimizedTravelMovement.getLength
	xIsOptimizedTravelMovement.item(i-1).setTextContent('false');
end
xIsOnlineStitchingEnabled = xDoc.getElementsByTagName('IsOnlineStitchingEnabled');
for i = 1:xIsOnlineStitchingEnabled.getLength()
	xIsOnlineStitchingEnabled.item(i-1).setTextContent('false');
end

%xPositions = xDoc.getElementsByTagName('SingleTileRegions').item(0);
%xSinglePosition = xPositions.getElementsByTagName('SingleTileRegion');
xPositions = xDoc.getElementsByTagName('SingleTileRegion');

figure(1);
clf(1);
hold on;
hOrg = plot( [ 0 ], [ 0 ], 'o', 'Color', [ 0 0 1 ], 'MarkerSize', 10, 'LineWidth', 2 );
hDir = plot( [ 0 ], [ 0 ], 'o', 'Color', [ 1 0 0  ], 'MarkerSize', 10, 'LineWidth', 2 );
hArr = plot( [ 0 ], [ 0 ], 'o', 'Color', [ 0 0.5 0  ], 'MarkerSize', 10, 'LineWidth', 2 );

global positions
positions = [];
for i = 1:xPositions.getLength()
	xPOSi = xPositions.item(i-1);
	if ( str2num( xPOSi.getElementsByTagName('IsUsedForAcquisition').item(0).getTextContent() ) )
		position = struct;
		position.X = str2num( xPOSi.getElementsByTagName('X').item(0).getTextContent() );
		position.Y = str2num( xPOSi.getElementsByTagName('Y').item(0).getTextContent() );
		position.Z = str2num( xPOSi.getElementsByTagName('Z').item(0).getTextContent() );
		positions = [ positions position ];

fprintf( 1, 'pos[%d] %s \n', i, num2str( [ position.X position.Y ] ) );

		DrawPos( position.X, position.Y, distw, disth );
	end
end

hold off;
axis equal;
set( gca, 'YDir', 'reverse' );
xlabel('X position (um)');
ylabel('Y position (um)');
legend( 'Origin', 'Direction', 'Array Direction' );

allpos = [];
orgI = [];
dirI = [];
dirC = [];
arrI = [];
arrC = 0;
arrw = distw;
arrh = disth;

minX = min( [ positions.X ] );
maxX = max( [ positions.X ] );

lind = find( [ positions.X ] < minX + distw/2 );
rind = find( maxX - distw/2 < [ positions.X ] );

[ TL, TLi ] = min( [ positions(lind).Y ] );
orgI = lind(TLi);
[ TR, TRi ] = min( [ positions(rind).Y ] );
dirI = [ rind(TRi) ];
dirC = [ 1 ];
if ( numel(lind) >= 2 )
	[ BL, BLi ] = max( [ positions(lind).Y ] );
	arrI = lind(BLi);
	arrC = 1;
end

global hClick
hold on;
hClick = plot( [ NaN ], [ NaN ], 'x', 'Color', [ 0 1 0 ], 'MarkerSize', 10, 'LineWidth', 2 );
hPos = line( [ NaN ], [ NaN ], 'Color', [ 1 0.5 0.5 ], 'LineWidth', 1 );
hold off;

while 1
	set( hClick, 'XData', [ NaN ], 'YData', [ NaN ] );
	set( hOrg, 'XData', [ positions(orgI).X	], 'YData', [ positions(orgI).Y ] );
	set( hDir, 'XData', [ positions(dirI).X	], 'YData', [ positions(dirI).Y ] );
	set( hArr, 'XData', [ positions(arrI).X	], 'YData', [ positions(arrI).Y ] );

	allpos = [];
	if ( ~isempty(orgI) )
		allpos = [ allpos positions(orgI) ];

		for i = 1:numel(dirI)
			if ( dirC(i) > 0 )
				if ( dirI(i) ~= orgI )
					dirVi = PositionAdd( positions(dirI(i)), PositionMultiply( positions(orgI), -1 ) );

					allpos0 = allpos;
					for j = 1:dirC(i)
						allpos = [ allpos PositionAdd( allpos0, PositionMultiply( dirVi, j/dirC(i) ) ) ];
					end
				end
			end
		end

		if ( ~isempty(arrI) && arrI ~= orgI && arrC > 0 )
			arrV = PositionAdd( positions(arrI), PositionMultiply( positions(orgI), -1 ) );

			allpos0 = allpos;
			for i = 1:arrC
				allpos = [ allpos ; PositionAdd( allpos0, PositionMultiply( arrV, i/arrC ) ) ];
			end

			arrw = max( distw, abs(arrV.X) * (arrC+1)/arrC );
			arrh = max( disth, abs(arrV.Y) * (arrC+1)/arrC );
		end
	end

	PosXData = [ NaN ];
	PosYData = [ NaN ];
	for i = 1:numel(allpos)
		[ xdatai, ydatai ] = RectData( allpos(i).X, allpos(i).Y, distw, disth );
		PosXData = [ PosXData xdatai NaN ];
		PosYData = [ PosYData ydatai NaN ];
	end
	set( hPos, 'XData', PosXData, 'YData', PosYData );
	fprintf( 1, 'Total %d positions generated. \n', numel(allpos) );
	
	ans = input( '[O]rigin; [D]irections; [A]rray; [C]ontinue ? ', 's' );
	if strcmpi( ans, 'C' )
		break;
	elseif strcmpi( ans, 'O' )
		disp( 'Reset Origin' );
		orgI = ClickPosition();
		dirI = [];
		dirC = [];
		arrI = [];
		arrC = 0;
	elseif strcmpi( ans, 'D' )
		disp( 'Set Up Directions' );
		if ~isempty(orgI)
			
%			dirI = [];
%			dirC = [];
%			while 1
%				posI = ClickPosition();
%				if ( isempty(posI) )
%					break;
%				end
%
%				temp = round( input( '# Position Arrays in this direction ? ' ) ) - 1;
%				if ( posI ~= orgI && ~isempty(temp) && temp >= 1 )
%					dirI = [ dirI posI ];
%					dirC = [ dirC temp ];
%					fprintf( 2, '%d Position Arrays Toward ( %f, %f ) \n', ...
%								dirC(end)+1, positions(dirI(end)).X, positions(dirI(end)).Y );
%				end
%			end

			i = 1;
			while 1
				if ( i <= numel(dirI) )
					posI = dirI(i);
					fprintf( 2, 'Direction [%d] -> ( %.3f, %.3f ) \n', i, positions(posI).X, positions(posI).Y );
				else
					fprintf( 1, 'Click to add a new direction. \n' );
					posI = ClickPosition();
					if ( isempty(posI) )
						break;
					end
				end

				if ( posI ~= orgI )
					temp = round( input( '# Position Arrays in this direction ? ' ) ) - 1;
					if ( ~isempty(temp) && temp >= 1 )
						dirI(i) = posI;
						dirC(i) = temp;
						fprintf( 2, '%d Position Arrays Toward ( %.3f, %.3f ) \n', dirC(i)+1, positions(posI).X, positions(posI).Y );
					elseif ( ~isempty(temp) && temp < 0 )
						if ( i <= numel(dirI) )
							dirI(i) = [];
							dirC(i) = [];
							fprintf( 2, 'Direction [%d]: deleted. \n', i );
							i = i - 1;
						end
					end
				end

				if ( i <= numel(dirI) )
					i = i + 1;
				end
			end
		end
	elseif strcmpi( ans, 'A' )
		disp( 'Set Up an Array' );
		if ~isempty(orgI)
			arrI = ClickPosition();
			if ( ~isempty(arrI) )
				arrC = round( input( '# Positions in an Array ? ' ) ) - 1;
				if ( arrI == orgI || isempty(arrC) || arrC < 1 )
					arrI = [];
					arrC = 0;
				end
			end
		end
	end
end

sz = size( allpos );
Narr = sz(2);
Npos = sz(1);

[ temp, sortI ] = sort( [ allpos( 1, : ).Y ], 'ascend' );
allpos = allpos( :, sortI );
[ temp, sortI ] = sort( [ allpos( 1, : ).X ], 'ascend' );
allpos = allpos( :, sortI );


xPositions = xDoc.getElementsByTagName('SingleTileRegions').item(0);
xPositionArrays = xDoc.getElementsByTagName('SingleTileRegionArrays').item(0);
while ( xPositionArrays.hasChildNodes() )
	xPositionArrays.removeChild( xPositionArrays.getFirstChild() );
end

for i = 1:Narr
	xPositionArray = xDoc.createElement('SingleTileRegionArray');
	xPositionArray.setAttribute( 'Name', [ 'A' num2str(i) ] );
	node = xDoc.createElement('CenterX');
	node.setTextContent( sprintf( '%.3f', mean( [ allpos(:, i).X ] ) ) );
	xPositionArray.appendChild( node );
	node = xDoc.createElement('CenterY');
	node.setTextContent( sprintf( '%.3f', mean( [ allpos(:, i).Y ] ) ) );
	xPositionArray.appendChild( node );
	node = xDoc.createElement('Width');
	node.setTextContent( sprintf( '%.3f', arrw ) );
	xPositionArray.appendChild( node );
	node = xDoc.createElement('Height');
	node.setTextContent( sprintf( '%.3f', arrh ) );
	xPositionArray.appendChild( node );
	node = xDoc.createElement('IsProtected');
	node.setTextContent( 'false' );
	xPositionArray.appendChild( node );
	node = xDoc.createElement('IsUsedForAcquisition');
	node.setTextContent( 'true' );
	xPositionArray.appendChild( node );
	node = xDoc.createElement('TemplateShapeId');
	xPositionArray.appendChild( node );
	node = xDoc.createElement('Contour');
	node.setAttribute( 'Type', 'Rectangle' );
	xPositionArray.appendChild( node );

	xPositionsi = xDoc.createElement('SingleTileRegions');
	for k = 1:Npos
		xPosition = xDoc.createElement('SingleTileRegion');
		xPosition.setAttribute( 'Name', [ 'P' num2str( Npos*(i-1) + k ) ] );
		node = xDoc.createElement('X');
		node.setTextContent( sprintf( '%.3f', allpos(k, i).X ) );
		xPosition.appendChild( node );
		node = xDoc.createElement('Y');
		node.setTextContent( sprintf( '%.3f', allpos(k, i).Y ) );
		xPosition.appendChild( node );
		node = xDoc.createElement('Z');
		node.setTextContent( sprintf( '%.3f', allpos(k, i).Z ) );
		xPosition.appendChild( node );
		node = xDoc.createElement('IsUsedForAcquisition');
		node.setTextContent( 'true' );
		xPosition.appendChild( node );
		xPositionsi.appendChild( xPosition );

		xPositions.appendChild( xPosition.cloneNode(true) );
	end
	xPositionArray.appendChild( xPositionsi );
	xPositionArrays.appendChild( xPositionArray );
end
xmlwrite( saveas, xDoc );
return;

function pos1 = PositionAdd( pos0, apos );
pos1 = reshape( pos0, 1, [] );
for i = 1:numel(pos1)
	pos1(i).X = pos1(i).X + apos.X;
	pos1(i).Y = pos1(i).Y + apos.Y;
	pos1(i).Z = pos1(i).Z + apos.Z;
end
pos1 = reshape( pos1, size(pos0) );
return;

function pos1 = PositionMultiply( pos0, n );
pos1 = reshape( pos0, 1, [] );
for i = 1:numel(pos1)
	pos1(i).X = pos1(i).X * n;
	pos1(i).Y = pos1(i).Y * n;
	pos1(i).Z = pos1(i).Z * n;
end
pos1 = reshape( pos1, size(pos0) );
return;

function [ xdata, ydata ] = RectData( x, y, w, h );
xdata = [ x-w/2 x-w/2 x+w/2 x+w/2 x-w/2 ];
ydata = [ y-h/2 y+h/2 y+h/2 y-h/2 y-h/2 ];
return;

function [ hPos, hRect ] = DrawPos( x, y, w, h );
[ xdata, ydata ] = RectData( x, y, w, h );
hRect = line( xdata, ydata, 'Color', [ 0.5 0.5 1 ], 'LineWidth', 1 );
hPos = plot( x, y, 'x', 'Color', [ 0 0 0 ], 'MarkerSize', 10, 'LineWidth', 2 );
return;

function posI = ClickPosition();
global distw disth
global positions
global hClick
posI = [];

while 1 
	[ gx, gy ] = ginput(1);
	if ( numel(gx) < 1 )
		return;
	end

	posX = [ positions.X ];
	posY = [ positions.Y ];
	[ mindist2, minI ] = min( ( gx(1) - posX ).^2 + ( gy(1) - posY ).^2 );
	if ~isempty(minI) && abs( gx(1)-positions(minI).X ) < distw && abs( gy(1)-positions(minI).Y ) < disth
		posI = minI;	
		set( hClick, 'XData', positions(posI).X, 'YData', positions(posI).Y );
	end
end
return;

