using RAYLASE.SPICE3;
using RAYLASE.SPICE3.ClientLib;
using RAYLASE.SPICE3.Utils;
using System;
using System.Diagnostics;

namespace PointAndShoot
{
	class Program
	{
		// insert the IP of your SP-ICE-3
		readonly string _CardIp = "192.168.2.138";
		ClientAPI _Client = new ClientAPI();

		static void Main( string[] args )
		{
			Program p = new Program();

			p._Client.Connect( p._CardIp );
			// Reset the card to its default settings:
			// This restores the following settings to the values that were last saved on the card:
			// - scanner configuration (such as field size, field correction, etc.)
			// - laser configuration (such as gate/LM timing parameters, power target, etc.)
			// - process variables (such as jump speed, settling times, mark speed, etc.)
			p._Client.System.ResetToDefaults();
			p._Client.Laser.ArmLaser( true );
			LaserConfig lc = p._Client.Laser.GetConfig();
			lc.PowerScale = 0.6;
			p._Client.Laser.SetConfig( lc );

			p.pointAndShootBidirectionally();
		}

		/// <summary>
		/// use the point and shoot algorithm to mark the bitmap (in this example a gradient bitmap is generated)
		/// to minimize the jump vecotrs, the alternating lines are marked in the opsite direction
		/// </summary>
		public void pointAndShootBidirectionally()
		{
			LaserConfig lc = _Client.Laser.GetConfig();
			lc.HotPowerTarget = PowerTarget.LmWidth;
			_Client.Laser.SetConfig( lc );

			ScannerConfig config = _Client.Scanner.GetConfig();
			config.Heads[0].Axes[0].TrackingError = 0;
			config.Heads[0].Axes[1].TrackingError = 0;
			config.Heads[0].Axes[2].TrackingError = 0;
			config.Heads[0].Axes[0].AccelerationTime = 0;
			config.Heads[0].Axes[1].AccelerationTime = 0;
			config.Heads[0].Axes[2].AccelerationTime = 0;
			double fromX = Math.Max( -30000, -0.4 * config.FieldSize.X );
			double toX = Math.Min( 59950, 0.4 * config.FieldSize.X );
			double fromY = Math.Max( -30000, -0.4 * config.FieldSize.Y );
			double toY = Math.Min( 29950, 0.4 * config.FieldSize.Y );
			_Client.Scanner.SetConfig( config );

			int imageWidth = 1200;
			int imageHeight = 200;

			ushort exposureTime = 10;

			int listIndex = 0;
			double jumpSpeed = 1.0;
			double markSpeed = 0.4;

			double spacingY = ( toY - fromY ) / ( imageHeight - 1 );

			// set process variables
			ProcessVariables pv = _Client.Process.GetVariables();
			pv.MaxDwellTime = 40;
			pv.MarkDelay = 0;
			pv.JumpDelay = 0;
			pv.PolyDelay = 50;
			pv.LaserOffDelay = 0;
			pv.LaserOnDelay = 0;
			_Client.Process.SetVariables( pv );

			CommandList list = new CommandList();
			list.AppendJumpSpeed( jumpSpeed );
			list.AppendJumpDelay( 0 );
			list.AppendMarkSpeed( markSpeed );
			list.AppendMarkDelay( 0 );
			list.AppendLmFrequency( 1.0 / 20 );
			list.AppendLmWidth( 20 );

			// generate bitmap and append it to the list
			int zero = 0;
			double powerSlope = (double)ushort.MaxValue / (double)( imageWidth - 1 );
			for ( int line = imageHeight; --line >= 0; )
			{
				double y = toY - line * spacingY;

				ushort[] powerValues = new ushort[imageWidth];
				if ( ( line & 1 ) != 0 )
				{
					for ( int idx = imageWidth; --idx >= 0; )
					{
						powerValues[imageWidth - idx - 1] = Convert.ToUInt16( powerSlope * idx );
						if ( powerValues[imageWidth - idx - 1] == 0 )
							zero++;
					}
					list.AppendPointAndShootLineAbs( toX, y, fromX, y, exposureTime, powerValues );
				}
				else
				{
					for ( int idx = imageWidth; --idx >= 0; )
					{
						powerValues[idx] = Convert.ToUInt16( powerSlope * idx );
						if ( powerValues[idx] == 0 )
							zero++;
					}
					list.AppendPointAndShootLineAbs( fromX, y, toX, y, exposureTime, powerValues );
				}
			}
			list.AppendLaserOff();
			list.AppendJumpAbs( toX, toY );

			// send the list to the card
			_Client.List.Set( listIndex, list );

			// estimate the mark time of one bitmap (assume top-right corner as the start point)
			double executionTimeMs = imageHeight * ( toX - fromX ) / jumpSpeed;
			executionTimeMs += exposureTime * ( ( imageWidth * imageHeight ) - zero );
			executionTimeMs += Math.Sqrt( Math.Pow( toX - fromX, 2 ) + Math.Pow( toY - fromY, 2 ) ) / jumpSpeed;
			executionTimeMs *= 0.001;
			_Client.Timeout = (int)executionTimeMs + 20000;

			// mark the bitmap several times, remove iterations when marking with laser
			Stopwatch sw = new Stopwatch();
			for ( int iteration = 0; ++iteration <= 4; )
			{
				Console.Out.WriteLine( "Iteration {0}: Beginning to mark...", iteration );

				sw.Restart();
				_Client.List.Execute( listIndex );

				int? id;
				_Client.List.WaitForListDone( out id );
				sw.Stop();

				Console.Out.WriteLine( "Execution done. ID={0}", id );
			}
		}
	}
}
