var MINIMUM_PANEL_WIDTH = 50;
var MINIMUM_PANEL_HEIGHT = 50;
var CROSS_CORNER_CHANCE = 0.25;

function Panel( left, top, right, bottom, pageArea )
{
	// closest distance from panel to centre of object
	this.distance = function( pageObject )
	{
		// default is null - returned if the panel cant contain the object
		var distance = null; 

		var thisPanelCanContainTheObject = this.getSize( ).canContain( pageObject.getMinimumSize( ) );

		if ( thisPanelCanContainTheObject )
		{
			// the ideal position of the centre of the object on the page
			var objectIdealCentre = new Position( this.pageArea.getLeft( ) + this.pageArea.getWidth( ) * pageObject.getIdealCentrePosition( ).getX( ),
								this.pageArea.getTop( ) + this.pageArea.getHeight( ) * pageObject.getIdealCentrePosition( ).getY( ) );
			
			var theObjectsIdealCentreIsToTheLeftOfThisPanel = objectIdealCentre.getX( ) < this.area.getLeft( );
			var theObjectsIdealCentreIsToTheRightOfThisPanel = this.area.getRight( ) < objectIdealCentre.getX( );
			var theObjectsIdealCentreIsAboveThisPanel = objectIdealCentre.getY( ) < this.area.getTop( );
			var theObjectsIdealCentreIsBelowThisPanel = this.area.getBottom( ) < objectIdealCentre.getY( );
			
			var horizontalDistance = 0;

			if ( theObjectsIdealCentreIsToTheLeftOfThisPanel )
			{
				horizontalDistance = this.area.getLeft( ) - objectIdealCentre.getX( );
			}
			else if ( theObjectsIdealCentreIsToTheRightOfThisPanel )
			{
				horizontalDistance = objectIdealCentre.getX( ) - this.area.getRight( );
			}
			// else the objects ideal centre is aligned with the panel in the x axis
			
			var verticalDistance = 0;

			if ( theObjectsIdealCentreIsAboveThisPanel )
			{
				verticalDistance = this.area.getTop( ) - objectIdealCentre.getY( );
			}
			else if ( theObjectsIdealCentreIsBelowThisPanel )
			{
				verticalDistance = objectIdealCentre.getY( ) - this.area.getBottom( );
			}
			//else the objects ideal centre is aligned with the panel in the y axis
			
			distance = Math.sqrt( horizontalDistance * horizontalDistance + verticalDistance * verticalDistance );
		}

		//informationPanel.addText( "distance from object id: " + pageObject.id + ", size: (" + pageObject.minimumWidth + ", " + pageObject.minimumHeight + ")/(" + pageObject.optimumWidth + ", " + pageObject.optimumHeight + ")(" + pageObject.maximumWidth + ", " + pageObject.maximumHeight + ") to panel (" + this.area.getLeft( ) + ", " + this.area.getTop( ) + ")->(" + this.area.getRight( ) + ", " + this.area.getBottom( ) + ") = (" + this.area.getWidth( ) + ", " + this.area.getHeight( ) + ") is " + distance );

		return distance;
	}
	
	this.add = function( pageObject )
	{
		informationPanel.addText( "Panel.add( pageObject )" );

		var newPanels = Array( );
		
		if ( this.getSize( ).canContain( pageObject.getMinimumSize( ) ) )
		{
			informationPanel.addText( "- Panel can contain object" );

			// size and position the image
			
			// if optimal size fits in panel
			if ( this.getSize( ).canContain( pageObject.getOptimumSize( ) ) )
			{
				informationPanel.addText( "-- Panel can contain object at optimal size" );

				// then size is optimal size
				pageObject.setSize( pageObject.getOptimumSize( ) );
			}
			else
			{
				informationPanel.addText( "-- Panel cannot contain object at optimal size" );

				// otherwise resize to fit panel
				pageObject.setSize( this.getSize( ) );
			}
			
			// if the image fits in the panel but will always create one or more empty panels
			if ( ( pageObject.getSize( ).getWidth( ) > this.getSize( ).getWidth( ) - MINIMUM_PANEL_WIDTH )
				|| ( pageObject.getSize( ).getHeight( ) > this.getSize( ).getHeight( ) - MINIMUM_PANEL_HEIGHT ) )
			{
				informationPanel.addText( "--- Panel can contain object but always creates (an) empty panel(s)" );
				
				// resize the image to be max size or fit exactly inside the panel or to fit exactly or leave space
				var bigSize = Size.intersection(
					new Size(
						this.getSize( ).getWidth( ),
						this.getSize( ).getHeight( ),
						pageObject.getAspectRatio( ) ),
					pageObject.getMaximumSize( ),
					pageObject.getAspectRatio( ) );
				
				var smallSize = Size.union(
					new Size(
						this.getSize( ).getWidth( ) - MINIMUM_PANEL_WIDTH,
						this.getSize( ).getHeight( ) - MINIMUM_PANEL_HEIGHT,
						pageObject.getAspectRatio( ) ),
					pageObject.getMinimumSize( ),
					pageObject.getAspectRatio( ) );

				smallSize = Size.intersection( smallSize, bigSize );

				informationPanel.addText( "---- bigSize: (" + bigSize.getWidth( ) + " x " + bigSize.getHeight( ) + ") = " + bigSize.getArea( ) );
				informationPanel.addText( "---- smallSize: (" + smallSize.getWidth( ) + " x " + smallSize.getHeight( ) + ") = " + smallSize.getArea( ) );

				if ( pageObject.getOptimumSize( ).getArea( ) != 0 && smallSize.getArea( ) != 0 )
				{
					if ( bigSize.getArea( ) >= smallSize.getArea( ) && bigSize.getArea( ) / pageObject.getOptimumSize( ).getArea( ) < pageObject.getOptimumSize( ).getArea( ) / smallSize.getArea( ) )
					{
						pageObject.setSize( bigSize );
						
						informationPanel.addText( "---- pageObject.setSize( bigSize )" );
					}
					else
					{
						pageObject.setSize( smallSize );

						informationPanel.addText( "---- pageObject.setSize( smallSize )" );
					}
				}
			}
			
			// position centre of image to be closest to optimal centre point
			var idealCentre = new Position( this.pageArea.getLeft( ) + this.pageArea.getWidth( ) * pageObject.getIdealCentrePosition( ).getX( ),
								this.pageArea.getTop( ) + this.pageArea.getHeight( ) * pageObject.getIdealCentrePosition( ).getY( ) );

			var possibleCentreArea = new Area( this.area.getLeft( ) + pageObject.getSize( ).getWidth( ) / 2,
										this.area.getTop( ) + pageObject.getSize( ).getHeight( ) / 2,
										this.area.getRight( ) - pageObject.getSize( ).getWidth( ) / 2,
										this.area.getBottom( ) - pageObject.getSize( ).getHeight( ) / 2 );

			var centreX = idealCentre.getX( );

			if ( idealCentre.getX( ) < possibleCentreArea.getLeft( ) )
			{
				centreX = possibleCentreArea.getLeft( );
			}
			else if ( possibleCentreArea.getRight( ) < idealCentre.getX( ) )
			{
				centreX = possibleCentreArea.getRight( );
			}
						
			var centreY = idealCentre.getY( );

			if ( idealCentre.getY( ) < possibleCentreArea.getTop( ) )
			{
				centreY = possibleCentreArea.getTop( );
			}
			else if ( possibleCentreArea.getBottom( ) < idealCentre.getY( ) )
			{
				centreY = possibleCentreArea.getBottom( );
			}
			
			pageObject.setCentrePosition( centreX, centreY );
			
			// if the image creates an empty panel at either edge then move the image to a distance of min image width or height away
			
			var reducedPanelArea = new Area( this.area.getLeft( ) + MINIMUM_PANEL_WIDTH, this.area.getTop( ) + MINIMUM_PANEL_HEIGHT, this.area.getRight( ) - MINIMUM_PANEL_WIDTH, this.area.getBottom( ) - MINIMUM_PANEL_HEIGHT );

			informationPanel.addText( "PanelArea: (" + this.area.getWidth( ) + " x " + this.area.getHeight( ) + ")" );
			informationPanel.addText( "reducedPanelArea: (" + reducedPanelArea.getWidth( ) + " x " + reducedPanelArea.getHeight( ) + ")" );

			if ( !reducedPanelArea.contains( pageObject.getArea( ) ) && reducedPanelArea.size.canContain( pageObject.getSize( ) ) )
			{
				informationPanel.addText( "- We need to move the object" );
			}

			// create new panels

			var subpanelComponents = Array( 8 );
			
			subpanelComponents[ 0 ] = Array( );
			subpanelComponents[ 0 ].left = this.area.getLeft( );
			subpanelComponents[ 0 ].top = this.area.getTop( );
			subpanelComponents[ 0 ].right = pageObject.getArea( ).getLeft( );
			subpanelComponents[ 0 ].bottom = pageObject.getArea( ).getTop( );
			
			subpanelComponents[ 1 ] = Array( );
			subpanelComponents[ 1 ].left = pageObject.getArea( ).getLeft( );
			subpanelComponents[ 1 ].top = this.area.getTop( );
			subpanelComponents[ 1 ].right = pageObject.getArea( ).getRight( );
			subpanelComponents[ 1 ].bottom = pageObject.getArea( ).getTop( );
			
			subpanelComponents[ 2 ] = Array( );
			subpanelComponents[ 2 ].left = pageObject.getArea( ).getRight( );
			subpanelComponents[ 2 ].top = this.area.getTop( );
			subpanelComponents[ 2 ].right = this.area.getRight( );
			subpanelComponents[ 2 ].bottom = pageObject.getArea( ).getTop( );
			
			subpanelComponents[ 3 ] = Array( );
			subpanelComponents[ 3 ].left = pageObject.getArea( ).getRight( );
			subpanelComponents[ 3 ].top = pageObject.getArea( ).getTop( );
			subpanelComponents[ 3 ].right = this.area.getRight( );
			subpanelComponents[ 3 ].bottom = pageObject.getArea( ).getBottom( );
			
			subpanelComponents[ 4 ] = Array( );
			subpanelComponents[ 4 ].left = pageObject.getArea( ).getRight( );
			subpanelComponents[ 4 ].top = pageObject.getArea( ).getBottom( );
			subpanelComponents[ 4 ].right = this.area.getRight( );
			subpanelComponents[ 4 ].bottom = this.area.getBottom( );
			
			subpanelComponents[ 5 ] = Array( );
			subpanelComponents[ 5 ].left = pageObject.getArea( ).getLeft( );
			subpanelComponents[ 5 ].top = pageObject.getArea( ).getBottom( );
			subpanelComponents[ 5 ].right = pageObject.getArea( ).getRight( );
			subpanelComponents[ 5 ].bottom = this.area.getBottom( );
			
			subpanelComponents[ 6 ] = Array( );
			subpanelComponents[ 6 ].left = this.area.getLeft( );
			subpanelComponents[ 6 ].top = pageObject.getArea( ).getBottom( );
			subpanelComponents[ 6 ].right = pageObject.getArea( ).getLeft( );
			subpanelComponents[ 6 ].bottom = this.area.getBottom( );
			
			subpanelComponents[ 7 ] = Array( );
			subpanelComponents[ 7 ].left = this.area.getLeft( );
			subpanelComponents[ 7 ].top = pageObject.getArea( ).getTop( );
			subpanelComponents[ 7 ].right = pageObject.getArea( ).getLeft( );
			subpanelComponents[ 7 ].bottom = pageObject.getArea( ).getBottom( );
			
			var currentSubpanel = null;
			var wrapLastSubpanel = false;
						
			for ( var cornerIndex = 0; cornerIndex < 4; ++cornerIndex )
			{
				if ( Math.random( ) <= CROSS_CORNER_CHANCE )
				{
					// finish
					if ( currentSubpanel != null )
					{
						// add subpanel
						newPanels.push( new Panel(
							currentSubpanel.left,
							currentSubpanel.top,
							currentSubpanel.right,
							currentSubpanel.bottom,
							this.pageArea ) );
					}
					
					// start
					// add ci*2
					currentSubpanel = Array( );
					currentSubpanel.left = subpanelComponents[ cornerIndex * 2 ].left;
					currentSubpanel.top = subpanelComponents[ cornerIndex * 2 ].top;
					currentSubpanel.right = subpanelComponents[ cornerIndex * 2 ].right;
					currentSubpanel.bottom = subpanelComponents[ cornerIndex * 2 ].bottom;
						
					// finish
						// add subpanel
					newPanels.push( new Panel(
						currentSubpanel.left,
						currentSubpanel.top,
						currentSubpanel.right,
						currentSubpanel.bottom,
						this.pageArea ) );
						
					// start
					// add ci*2+1
					currentSubpanel = Array( );
					currentSubpanel.left = subpanelComponents[ cornerIndex * 2 + 1 ].left;
					currentSubpanel.top = subpanelComponents[ cornerIndex * 2 + 1 ].top;
					currentSubpanel.right = subpanelComponents[ cornerIndex * 2 + 1 ].right;
					currentSubpanel.bottom = subpanelComponents[ cornerIndex * 2 + 1 ].bottom;
				}
				else if ( Math.random( ) <= 0.5 )
				{
					// finish
					if ( currentSubpanel != null )
					{
						// add subpanel
						newPanels.push( new Panel(
							currentSubpanel.left,
							currentSubpanel.top,
							currentSubpanel.right,
							currentSubpanel.bottom,
							this.pageArea ) );
					}
					
					// start
					// add ci*2
					// add ci*2+1
					currentSubpanel = Array( );
					currentSubpanel.left = Math.min( subpanelComponents[ cornerIndex * 2 ].left, subpanelComponents[ cornerIndex * 2 + 1 ].left );
					currentSubpanel.top = Math.min( subpanelComponents[ cornerIndex * 2 ].top, subpanelComponents[ cornerIndex * 2 + 1 ].top );
					currentSubpanel.right = Math.max( subpanelComponents[ cornerIndex * 2 ].right, subpanelComponents[ cornerIndex * 2 + 1 ].right );
					currentSubpanel.bottom = Math.max( subpanelComponents[ cornerIndex * 2 ].bottom, subpanelComponents[ cornerIndex * 2 + 1 ].bottom );
				}
				else
				{
					if ( currentSubpanel != null )
					{
						// add ci*2
						var newCurrentSubpanel = Array( );
						newCurrentSubpanel.left = Math.min( currentSubpanel.left, subpanelComponents[ cornerIndex * 2 ].left );
						newCurrentSubpanel.top = Math.min( currentSubpanel.top, subpanelComponents[ cornerIndex * 2 ].top );
						newCurrentSubpanel.right = Math.max( currentSubpanel.right, subpanelComponents[ cornerIndex * 2 ].right )
						newCurrentSubpanel.bottom = Math.max( currentSubpanel.bottom, subpanelComponents[ cornerIndex * 2 ].bottom );
						currentSubpanel = newCurrentSubpanel;
						
						// finish
							// add subpanel
						newPanels.push( new Panel(
							currentSubpanel.left,
							currentSubpanel.top,
							currentSubpanel.right,
							currentSubpanel.bottom,
							this.pageArea ) );
					}
					else
					{
						wrapLastSubpanel = true;
					}
					
					// start
					// add ci*2+1
					currentSubpanel = Array( );
					currentSubpanel.left = subpanelComponents[ cornerIndex * 2 + 1 ].left;
					currentSubpanel.top = subpanelComponents[ cornerIndex * 2 + 1 ].top;
					currentSubpanel.right = subpanelComponents[ cornerIndex * 2 + 1 ].right;
					currentSubpanel.bottom = subpanelComponents[ cornerIndex * 2 + 1 ].bottom;
				}				
			}

			if ( wrapLastSubpanel )
			{
				var newCurrentSubpanel = Array( );
				newCurrentSubpanel.left = Math.min( currentSubpanel.left, subpanelComponents[ 0 ].left );
				newCurrentSubpanel.top = Math.min( currentSubpanel.top, subpanelComponents[ 0 ].top );
				newCurrentSubpanel.right = Math.max( currentSubpanel.right, subpanelComponents[ 0 ].right );
				newCurrentSubpanel.bottom = Math.max( currentSubpanel.bottom, subpanelComponents[ 0 ].bottom );
				currentSubpanel = newCurrentSubpanel;
			}
						
			//finish
				// add subpanel
			newPanels.push( new Panel(
				currentSubpanel.left,
				currentSubpanel.top,
				currentSubpanel.right,
				currentSubpanel.bottom,
				this.pageArea ) );
		}
		
		// remove too small panels
		
		var newGoodPanels = Array( );
		
		for ( var panelsSeen = 0; panelsSeen < newPanels.length; ++panelsSeen )
		{
			//if ( newPanels[ panelsSeen ].getSize( ).getWidth( ) >= MINIMUM_PANEL_WIDTH && newPanels[ panelsSeen ].getSize( ).getHeight( ) >= MINIMUM_PANEL_HEIGHT )
			{
				newGoodPanels.push( newPanels[ panelsSeen ] );
			}
		}
		
		return newGoodPanels;
	}
	
	this.getSize = function( )
	{
		return new Size( this.area.getRight( ) - this.area.getLeft( ), this.area.getBottom( ) - this.area.getTop( ) );
	}

	/////////////////////////////////////////////////////////////

	this.area = new Area( left, top, right, bottom );
	this.pageArea = pageArea;
}

