using System;
using BinaryIO;


namespace Blaze{
	
	/// <summary>
	/// A curve sampler. Steps along a curve (along x, reading y) at regular values.
	/// X ranges from 0-1.
	/// </summary>
	
	public class CurveSampler : MappedShapeSampler{
		
		public VectorPath Path;
		/// <summary>The current point we're at whilst stepping through this sampler.</summary>
		public VectorPoint Current;
		/// <summary>The distance stepped since a reset.</summary>
		public float DistanceStepped;
		/// <summary>The current value of this sampler. 
		/// Must have been advancing it for this to be available.</summary>
		public float CurrentValue;
		
		
		public CurveSampler(VectorPath path){
			Path=path;
		}
		
		/// <summary>Goes to a particular t value. 
		/// Note that t should usually be bigger than the previous Goto request 
		/// (backward seeking isn't super efficient).</summary>
		public void Goto(float t,bool readValue){
			
			if(t<DistanceStepped){
				
				Reset();
				Advance(t,readValue);
				
			}else{
				
				Advance(t-DistanceStepped,readValue);
				
			}
			
		}
		
		/// <summary>Bakes this curve into a set of values of the given size.</summary>
		public float[] Bake(int size){
		
			// Create:
			float[] data=new float[size];
			
			// Bake:
			Bake(data);
			
			return data;
			
		}
		
		/// <summary>Bakes this curve into a set of values.</summary>
		public void Bake(float[] data){
			
			// Walk along the path, reading the x/y values as we go.
			// Note that x is "progress" and it's 0-1. (Standard blade curve).
			Reset();
			
			int size=data.Length;
			
			if(size==1){
				data[0]=CurrentValue;
				return;
			}
			
			float delta=1f / (float)(size-1f);
			
			for(int i=0;i<size;i++){
				
				// Get the value:
				data[i]=CurrentValue;
				
				// Walk the sampler:
				Advance(delta,true);
				
			}
			
		}
		
		/// <summary>Resets the stepping through this sampler.</summary>
		public void Reset(){
			
			Current=Path.FirstPathNode;
			DistanceStepped=0f;
			
			// Write the value:
			if(Current!=null){
				CurrentValue=Current.Y;
				
				if(Current.Next!=null){
					Current.Next.SetupSampler(this);
				}
				
			}else{
				CurrentValue=0f;
			}
			
		}
		
		/// <summary>Advances this sampler by the given amount.</summary>
		public virtual void Advance(float by,bool readValue){
			
			// Update the distance stepped:
			DistanceStepped+=by;
			
			if(Current==null){
				return;
			}
			
			bool changed=false;
			
			while(Current.Next!=null){
				
				// Get the current x point:
				float x=Current.Next.X;
				
				if(DistanceStepped<x){
					
					break;
				}
				
				// Hop to the next one:
				Current=Current.Next;
				
				changed=true;
				
			}
			
			if(readValue){
				
				if(Current.Next==null){
					
					// Apply current - This is where clamp comes from:
					CurrentValue=Current.Y;
					
					return;
				}
				
				if(changed){
					Current.Next.SetupSampler(this);
				}
				
				// What's the difference between next and this?
				float deltaX=Current.Next.X-Current.X;
				
				// 0-1 progress factor:
				float progress=(DistanceStepped-Current.X) / deltaX;
				
				CurrentValue=Current.Next.SampleMapped(this,progress);
				
			}
			
		}
		
	}
	
}