<?php
/*******************************************************************************
 * FRESHIZER -> WP Image Resizer Script
 * =============================================================================
 * 
 * @license GNU version 2
 * @author freshace
 * @version 1.5
 * @link http://github.com/boobslover/freshizer
/*******************************************************************************
 * SETTINGS, PLEASE CHANGE ONLE THESE 3 CONSTANTS
 ******************************************************************************/
// NOTE
// ====
// please notice, that the time is in SECONDS. There are not allowed math
// operations in the definition. So instead of writing:
// = 60(sec) * 60(min) * 24(hr) * 7(days); you have to write:
// = 604800; // seconds in 7 days 


// CACHE TIME
// ==========
// When the new (cached) file is older than this time, script automatically
// checks, if the old file has been changed. If not, then ve serve cached file
// again. If yes, cached file is deleted and resized again.
define('CACHE_TIME', 604800);

// CACHE DELETE FILES AFTER
// ========================
// Hard delete files ( not only compare if the original file has been changed,
// but hardly delete from caching folder ), every X seconds. Please fill a large
// number, because cached files runs much more speedely
define('CACHE_DELETE_FILES_AFTER',10000000);

// CACHE DELETE FILES - check every X hits
// =======================================
// How often do we check if there are files which should be hard deleted ?
// Optimal is approx 400 - 500 hits
define('CACHE_DELETE_FILES_check_every_x_hits',150);



class blFile {
	CONST POINTER_END = 'pend';
	
	private $_handle = null;
	private $_fileSize = null;
	private $_path = null;
	private $_writeBuffer = '';

/*----------------------------------------------------------------------------*/
/* FUNCTIONS PUBLIC
/*----------------------------------------------------------------------------*/

	public function __construct( $handle, $path ) {
		$this->_setHandle( $handle );
		$this->_setPath( $path );
	}

	public function readAll() {
		if( $this->getFileSize() > 0 )
			return (fread( $this->getHandle(), $this->getFileSize() ));
		else 
			return null;
	}
	public function read( $size ) {
		if( $this->getFileSize() > 0 )
			return fread( $this->getHandle(), $size );
		else
			return null;
	}
	public function readAllAndClose() {
		$fileContent = $this->readAll();
		$this->closeFile();

		return $fileContent;
	}
	
	/**
	 * @param string $content
	 * @return blFile
	 */
	public function write( $content ) {
		fwrite( $this->getHandle(), ( $content ) );
		return $this;
	}
	
	public function writeBuffered( $content ) {
		$this->_setWriteBuffer( $content );
		return $this;
	}
	
	/*public function __destruct() {
		var_dump($this);
		if( $this->_writeBuffer != '' ) {
			$this->write( $this->_writeBuffer ) ;
		}
		
		$this->closeFile();
	}*/
	
	/**
	 * @return blFile
	 */
	public function truncate() {
		ftruncate( $this->getHandle(), 0);
		$this->pointerStart();
		return $this;
	}

	public function closeFile() {
		if( $this->getHandle() !== null ) {
			fclose( $this->getHandle() );
			$this->_setHandle(null);
		}
	}
	
	/**
	 * @return blFile
	 */
	public function pointerStart() {
		$this->_movePointer( 0 );
		return $this;
	}
	
	/**
	 * @return blFile
	 */
	public function pointerEnd() {
		$this->_movePointer( self::POINTER_END );
		return $this;
	}
	
	/**
	 * @param int $where
	 * @return blFile
	 */
	public function pointerTo( $where ) {
		return $this->_movePointer( $where );
		return $this;
	}

	
/*----------------------------------------------------------------------------*/
/* FUNCTIONS PRIVATE
/*----------------------------------------------------------------------------*/
	private function _movePointer( $where ) { 
		if( $where == self::POINTER_END ) {
			fseek( $this->getHandle(), 0, SEEK_END);
		} else {
			fseek( $this->getHandle(), $where, SEEK_SET);
		}
	}
	
/*----------------------------------------------------------------------------*/
/* SETTERS AND GETTERS
/*----------------------------------------------------------------------------*/

	private function _setWriteBuffer( $content ) {
		$this->_writeBuffer = $content;
	}
	
	private function _getWriteBuffer() {
		return $this->_writeBuffer;
	}
	
	public function getHandle() {
		return $this->_handle;
	}

	private function _setHandle( $handle ) {
		$this->_handle = $handle;
	}

	public function getPath() {
		return $this->_path;
	}

	private function _setPath( $path ) {
		$this->_path = $path;
	}

	public function getFileSize() {
		if( $this->_fileSize == null ) {
			$this->_fileSize = filesize( $this->getPath() );
		}

		return $this->_fileSize;
	}
}


class blFileSystem {
	private $_errors = array();
/*----------------------------------------------------------------------------*/
/* FUNCTIONS PUBLIC
/*----------------------------------------------------------------------------*/	
	
	/**
	 * Trying to open file. If neccessary, creates dir and file automatically 
	 * 
	 * @param string $path
	 * @param bool $writing
	 * @return blFile
	 */
	public function openFile( $path, $writing = false ) {
	if( file_exists( $path ) ) {
			$mode = ( $writing ) ? 'r+' : 'r';
		} else {
			$mode = ( $writing ) ? 'c+' : 'c';
		}
		return $this->_openFile( $path, $mode );
	}
	
	/**
	 * Open file, if exists, truncate
	 * @param string $path
	 * @param bool $writing
	 * @return blFile
	 */
	public function createFile( $path, $writing = false ) {
		$mode = ( $writing ) ? 'c+' : 'c';
		return $this->_openFile( $path, $mode );	
	}
	
	public function deleteFile( $path ) {}
	
	public function createDir( $path ) {
		if( mkdir( $path, 0777, true ) === false ) {
			$this->_addError( 'Unable to create DIR :'. $path );
		}
	}
	
	public function saveImage( $image, $path ) {
		$pinfo = pathinfo( $path );
		$ext = $pinfo['extension'];
		$return = null;
	
		switch( $ext ) {
			case 'jpg':
				$return = imagejpeg($image, $path, 90 );
				break;
			case 'jpeg':
				$return = imagejpeg($image, $path, 90 );
				break;
			case 'png':
				$return = imagepng( $image, $path, 0 );
				break;
					
			case 'gif':
				$return = imagegif( $image, $path );
				break;
		}
	
		return $return;
	
	}	

/*----------------------------------------------------------------------------*/
/* FUNCTIONS PRIVATE
/*----------------------------------------------------------------------------*/	
	
	private function _openFile( $path, $mode ) {
		$pathInfo = pathinfo( $path );
		$dirname = $pathInfo['dirname'];
		$file = null;
		
		if( !is_dir( $dirname ) ) {
			$this->createDir( $dirname );
		}
		
		$fileHandler = fopen( $path, $mode);
		$file = new blFile( $fileHandler, $path);
	
		return $file;
	}

/*----------------------------------------------------------------------------*/
/* SETTERS AND GETTERS
/*----------------------------------------------------------------------------*/
	public function getErorrs() {
		return $this->_errors;
	}
	
	private function _addError( $error ) {
		$this->_errors[] = $error;
	}
	
}


interface blIConnection {
	public function getContent( $url );
}


class blConnectionAdapteur implements blIConnection {
	/**
	 * @var blIConnection
	 */
	private $_connectionMethod = null;
	
/*----------------------------------------------------------------------------*/
/* PUBLIC FUNCTIONS
/*----------------------------------------------------------------------------*/	
	
	public function getContent( $url ) {
		return $this->_getConnectionMethod()->getContent($url);
	}
/*----------------------------------------------------------------------------*/
/* PRIVATE FUNCTIONS
/*----------------------------------------------------------------------------*/	
	
	private function _createProperConnection() {
		if( ini_get('allow_url_fopen') ) {
			$this->_setConnectionMethod( new blConnectionFopen() );
		} else if( function_exists( 'curl_init') ) {
			$this->_setConnectionMethod( new blConnectionCurl() );	
		}
	}
	
/*----------------------------------------------------------------------------*/
/* GETTERS AND SETTERS
/*----------------------------------------------------------------------------*/
	
	private function _setConnectionMethod( blIConnection $connectionMethod ) {
		$this->_connectionMethod = $connectionMethod;
	}
	
	/**
	 * @return blIConnection
	 */
	private function _getConnectionMethod() {
		if( $this->_connectionMethod == null ) {
			$this->_createProperConnection();
		}
		return $this->_connectionMethod;
	}
}


class blConnectionCurl implements blIConnection {
	public function getContent( $url ) {
		$ch = curl_init();
		$timeout = 5;
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
		$data = curl_exec($ch);
		curl_close($ch);
		
		return $data;		
	}
}


class blConnectionFopen implements blIConnection {
	public function getContent( $url ) {
		
		$handle = fopen( $url, 'rb' );
		$fileContent = '';
		if( $handle !== false ) {
			while (!feof($handle)) {
				$fileContent .= fread($handle, 8192);
			}
			fclose( $handle );
		}
		return $fileContent;
	}
}


class blDownloader {
	/**
	 * @var blIConnection
	 */
	private $_connectionMethod = null;
	
	public function getContent( $url ) {
		return $this->_getConnectionMethod()->getContent($url);
               
	}
	/**
         * 
         * @param blIConnection $connectionMethod
         */
	private function _setConnectionMethod( blIConnection $connectionMethod ) {
		$this->_connectionMethod = $connectionMethod;
	}
	
	/**
	 * @return blIConnection
	 */
	private function _getConnectionMethod() {
		if( $this->_connectionMethod == null ) {
			$this->_setConnectionMethod( new blConnectionAdapteur() );
		}
		return $this->_connectionMethod;
	}
}


class blImgCache {
	CONST CACHE_FILENAME = 'img_caching_info.frs';
	
	
	/**
	 * @var blFileSystem
	 */
	private $_fileSystem = null;
	
	/**
	 * @var blFile
	 */
	private $_cacheFile = null;
	
	private $_cacheFileUnparsed = null;
	
	private $_cacheFileParsed = null;
	
	private $_cacheFileDir = null;
	
	public function __construct( blFileSystem $fileSystem, $cacheFileDir ) {
		
		$this->_setFileSystem($fileSystem);
		$this->_setCacheFileDir($cacheFileDir . self::CACHE_FILENAME );
		
		$this->_loadCacheFile();
		$this->_unparseCacheFile();
		
	}
	
	public function addCachedFileRemote( $urlNew, $pathNew, $urlOld ) {
		$cacheFileUnparsed = $this->_getCacheFileUnparsed();
		
		if( $this->_cacheFileUnparsed == null ) {
			$this->_cacheFileUnparsed = new stdClass();
		}
		if( !isset( $cacheFileUnparsed->remoteDataHolder[ $urlOld ] ) ) {
			$cachedFile = new stdClass();
			$cachedFile->urlNew = $urlNew;
			$cachedFile->pathNew = $pathNew;
			$cachedFile->urlOld = $urlOld;
			$cachedFile->timestamp = time();
			
			$cacheFileUnparsed->remoteDataHolder[ $cachedFile->urlOld] = $cachedFile;
		}
	}
	
	public function addCachedFile( $urlNew, $urlOld, $pathNew, $pathOld, $remote = false ) {
		$cacheFileUnparsed = $this->_getCacheFileUnparsed();
		
		if( $this->_cacheFileUnparsed == null ) {
			$this->_cacheFileUnparsed = new stdClass();
		}
		if( !isset( $cacheFileUnparsed->dataHolder[ $urlNew ] ) ) {
			$cachedFile = new stdClass();
			$cachedFile->urlNew = $urlNew;
			$cachedFile->urlOld = $urlOld;
			$cachedFile->pathNew = $pathNew;
			$cachedFile->pathOld = $pathOld;
			$cachedFile->remote = $remote;
			$cachedFile->timestamp = time();
			
			$cacheFileUnparsed->dataHolder[ $cachedFile->urlNew] = $cachedFile;
		}
		
		
	} 
	
	public function deleteCacheInfo( $urlNew ) {
		
		
		unset( $this->_getCacheFileUnparsed()->dataHolder[ $urlNew ] );
	}
	
	public function deleteRemoteCacheInfo( $url ) {
		unset( $this->_getCacheFileUnparsed()->remoteDataHolder[ $url ] );
	}
	
	public function getCacheInfo( $urlNew ) {
		$cacheFileUnparsed = $this->_getCacheFileUnparsed();
		if( isset( $cacheFileUnparsed->dataHolder[ $urlNew ] ) ) {
			$cachedImageInfo = $cacheFileUnparsed->dataHolder[ $urlNew ];
			$cachedImageInfo->valid = $this->_checkExpiration($cachedImageInfo);	
			return $cacheFileUnparsed->dataHolder[ $urlNew ];
		} else {
			return null;
		}
	}
	
	public function touchCachedFile( $urlNew ) {
		$cacheFileUnparsed = $this->_getCacheFileUnparsed();
		$cacheFileUnparsed->dataHolder[ $urlNew ]->valid = true;
		$cacheFileUnparsed->dataHolder[ $urlNew ]->timestamp = time();
	}
	
	public function getRemoteCacheInfo( $urlOld ) {
		$cacheFileUnparsed = $this->_getCacheFileUnparsed();
		if( isset( $cacheFileUnparsed->remoteDataHolder[ $urlOld ] ) ) {
			$cachedImageInfo = $cacheFileUnparsed->remoteDataHolder[ $urlOld ];
			$cachedImageInfo->valid = $this->_checkExpiration($cachedImageInfo);
			return $cacheFileUnparsed->remoteDataHolder[ $urlOld ];
		} else {
			return null;
		}
	}
	
	private function _checkExpiration( stdClass $cachedImageInfo ) {
		$currentTimestamp = time();
		$oldTimestamp = $cachedImageInfo->timestamp;
		
		if( ( $oldTimestamp + CACHE_TIME ) < $currentTimestamp ) {
			return false;
		} else {
			return true;
		}
	}
	
	/*public function deleteCacheInfo( $urlNew ) {
		$cacheFileUnparsed = $this->_getCacheFileUnparsed();
		unset( $cacheFileUnparsed->dataHolder[ $urlNew ] );
		
	}*/
	
	public function __destruct() {
		
		$this->saveCacheFile();
	}
	
	public function saveCacheFile() {
		
		$this->_parseCacheFile();
		$this->_saveCacheFile();
	}
	
	private function _parseCacheFile() {
		$cacheFileParsed = serialize( $this->_getCacheFileUnparsed() );
		$this->_setCacheFileParsed( $cacheFileParsed );
	}
	
	private function _saveCacheFile() {
		if( $this->_getCacheFile()->getHandle() == null ) return ;
		$this->_getCacheFile()
				->truncate()
				->write( $this->_getCacheFileParsed() )
				->closeFile();
	}
	
	
	private function _loadCacheFile() {
		$cacheFile = $this->_getFileSystem()->openFile( $this->_getCacheFileDir(), true);
		
		$this->_setCacheFile( $cacheFile );
		$this->_setCacheFileParsed( $cacheFile->readAll() );
		
	}
	
	private function _unparseCacheFile() {
		if( $this->_getCacheFileParsed() != '') {
			$cacheFileContentUnparsed = unserialize( $this->_getCacheFileParsed() );
			$cacheFileContentUnparsed->hitsAfterLastDelete++;
			
			$this->_setCacheFileUnparsed( $cacheFileContentUnparsed );
		} else {
			$cacheFileContentUnparsed = new stdClass();
			$cacheFileContentUnparsed->hitsAfterLastDelete = 1;
			$this->_setCacheFileUnparsed( $cacheFileContentUnparsed );
		}
		
		if( $cacheFileContentUnparsed->hitsAfterLastDelete >= CACHE_DELETE_FILES_check_every_x_hits ) {
			$this->_hardDeleteCache();
		}
	}
	
	private function _hardDeleteCache() {
		//var_dump(CACHE_DELETE_FILES_check_every_x_hits);
		$unsetArray = array();
		if( !empty( $this->_getCacheFileUnparsed()->dataHolder ) ) {
			foreach( $this->_getCacheFileUnparsed()->dataHolder as $url => $fileData ) {
				//pathNew, timestamp
				if( ( $fileData->timestamp  + CACHE_DELETE_FILES_AFTER ) <= time() ) {
					$unsetArray[] = $url;
					unlink( $fileData->pathNew);
				}
			}
		}
		foreach( $unsetArray as $oneUrl ) {
			unset ($this->_getCacheFileUnparsed()->dataHolder[ $oneUrl ] );
		}
		
		$unsetArray = array();
		if( !empty( $this->_getCacheFileUnparsed()->remoteDataHolder ) ) {
			foreach( $this->_getCacheFileUnparsed()->remoteDataHolder as $url => $fileData ) {
				//pathNew, timestamp
				if( ( $fileData->timestamp  + CACHE_DELETE_FILES_AFTER ) <= time() ) {
					$unsetArray[] = $url;
					unlink( $fileData->pathNew);
				}
			}
		}
		foreach( $unsetArray as $oneUrl ) {
			unset ($this->_getCacheFileUnparsed()->remoteData[ $oneUrl ] );
		}
		$this->_getCacheFileUnparsed()->hitsAfterLastDelete = 0;
	}
	
	
	private function _setCacheFileParsed( $cacheFileParsed ) {
		$this->_cacheFileParsed = $cacheFileParsed;
	}
	
	private function _getCacheFileParsed() {
		return $this->_cacheFileParsed;
	}
	
	private function _setCacheFileUnparsed( $cacheFileUnparsed ) {
		$this->_cacheFileUnparsed = $cacheFileUnparsed;
	}
	
	private function _getCacheFileUnparsed() {
		return $this->_cacheFileUnparsed;
	}
	
	private function _setCacheFileDir( $cacheFileDir) {
		$this->_cacheFileDir = $cacheFileDir;
	}
	
	private function _getCacheFileDir() {
		return $this->_cacheFileDir;
	}
	
	private function _setCacheFile( blFile $cacheFile ) {
		$this->_cacheFile = $cacheFile;
	}
	
	/**
	 * @return blFile
	 */
	private function _getCacheFile() {
		return $this->_cacheFile;
	}
	
	private function _setFileSystem( blFileSystem $fileSystem ) {
		$this->_fileSystem = $fileSystem;
	}
	
	/**
	 * 
	 * @return blFileSystem
	 */
	private function _getFileSystem() {
		return $this->_fileSystem;
	}
}


class blImgDownloader {
	/**
	 * @var blFileSystem
	 */
	private $_fileSystem = null;
	
	/**
	 * @var blInputStreamAdapteour
	 */
	private $_inputStream = null;
	
	public function __construct( blFileSystem $fileSystem, blInputStreamAdapteour $inputStreamAdapter ) {
		$this->_setFileSystem( $fileSystem );
		$this->_setInputStream( $inputStreamAdapter );
	}
	
	public function downloadImage( $originalPath, $newPath ) {
		$img = $this->_getInputStream()->open( $originalPath )->readAll();
		if( $img != null ) {
			$this->_getFileSystem()->createFile( $newPath, true)->write( $img )->closeFile();
		}
	}
	
	private function _setInputStream( blInputStreamAdapteour $inputStreamAdapter ) {
		$this->_inputStream = $inputStreamAdapter;
	}
	
	/**
	 * @return blInputStreamAdapteour
	 */
	private function _getInputStream() {
		return $this->_inputStream;
	}
	
	private function _setFileSystem( blFileSystem $fileSystem ) {
		$this->_fileSystem = $fileSystem;
	}
	/**
	 * @return blFileSystem
	 */
	private function _getFileSystem() {
		return $this->_fileSystem;
	}
}


interface blIInputStream {
	public function open( $path );
	public function readAll();
	
}


class blInputStreamFile implements blIInputStream {
	/**
	 * @var blFileSystem
	 */
	private $_fileSystem = null;
	
	/**
	 * @var blFile
	 */
	private $_openedFile = null;
	
	public function __construct() {
		
	}
	
	/**
	 * (non-PHPdoc)
	 * @see blIInputStream::open()
	 */
	public function open( $path ) {
		$file = $this->_getFileSystem()->openFile($path);
		$this->_setFile( $file );
		return $this;
	}
	
	public function readAll() { 
		return $this->_getFile()->readAllAndClose();
	}
	
/*----------------------------------------------------------------------------*/
/* SETTERS AND GETTERS
/*----------------------------------------------------------------------------*/
	private function _setFileSystem( blFileSystem $fileSystem ) {
		$this->_fileSystem = $fileSystem;
	}
	
	/**
	 * @return blFileSystem
	 */
	private function _getFileSystem() {
		if( $this->_fileSystem == null ) {
			$this->_setFileSystem( new blFileSystem() );
		}
		
		return $this->_fileSystem;
	}
	
	private function _setFile( blFile $file ) {
		$this->_openedFile = $file;
	}
	
	/**
	 * @return blFile
	 */
	private function _getFile() {
		return $this->_openedFile;
	}
}


class blInputStreamHttp implements blIInputStream {
	/**
	 * @var blDownloader
	 */
	private $_downloader = null;
	private $_pageContent = '';
	
	public function open( $path ) {
		$content = $this->_getDownloader()->getContent( $path );
		$this->_setPageContent( $content );
	}
	
	public function readAll() {
		return $this->_getPageContent();
	}
	
	/**
	 * @return blDownloader
	 */
	private function _getDownloader() {
		if( $this->_downloader == null ) {
			$this->_downloader = new blDownloader();
		}
		
		return $this->_downloader;
	}
	
	private function _setPageContent( $pageContent ) {
		$this->_pageContent = $pageContent;
	}
	
	private function _getPageContent() {
		return $this->_pageContent;
	}
}


class blInputStreamAdapteour implements blIInputStream {
	/**
	 * 
	 * @var blIInputStream
	 */
	private $_inputStream = null;
	
/*----------------------------------------------------------------------------*/
/* PUBLIC FUNCTIONS
/*----------------------------------------------------------------------------*/
		
	public function open( $path ) {
		$this->_createInputStream( $path );
		$this->_getInputStream()->open($path);
		return $this;
	}
	
	public function readAll() {
		return $this->_getInputStream()->readAll();
	}
	
/*----------------------------------------------------------------------------*/
/* PRIVATE FUNCTIONS
/*----------------------------------------------------------------------------*/	
	private function _createInputStream( $path ) {
		if( strpos( $path, 'http://') !== false ) {
			$this->_setInputStream( new blInputStreamHttp() );
		} else {
			$this->_setInputStream( new blInputStreamFile() );
		}
	}
/*----------------------------------------------------------------------------*/
/* SETTERS AND GETTERS
/*----------------------------------------------------------------------------*/
	
	private function _setInputStream(  blIInputStream $inputStream ) {
		$this->_inputStream = $inputStream;
	}
	
	private function _getInputStream() {
		return $this->_inputStream;
	}
}


class fImgOneData {
	public $path = null;
	public $url = null;
	public $filename = null;
	public $width = null;
	public $height = null;
	public $timestamp = null;
	public $crop = null;
}

class fImgData {
	/**
	 * 
	 * @var fImgOneData
	 */
	public $new = null;
	
	/**
	 * 
	 * @var fImgOneData
	 */
	public $old = null;
	
	public $remote = false;
	public $ready = false;
	
	public function __construct() {
		$this->new = new fImgOneData();
		$this->old = new fImgOneData();
	}
	
}




class fImgDeliverer {
	/**
	 * @var blFileSystem
	 */
	private $_fileSystem = null;
	
	
	/**
	 * 
	 * @var blInputStreamAdapteour
	 */
	private $_inputStream = null;
	
	/**
	 * @var blImgCache
	 */
	private $_imgCache = null;
	
	/**
	 * 
	 * @var fImgPathPredictor
	 */
	private $_imgPredictor = null;
	
	
	/**
	 * 
	 * @var blImgDownloader
	 */
	private $_imgDownloader = null;
	
	private $_uploadDir = null;
	
	private $_uploadUrl = null;
	
	/**
	 * 
	 * @var fImgNamer
	 */
	private $_imgNamer = null;
	
	public function __construct( blFileSystem $fileSystem,  $inputStream, blImgCache $imgCache, $uploadDir, $uploadUrl ) {
		$this->_setFileSystem( $fileSystem );
		$this->_setInputStream( $inputStream );
		$this->_setImgCache( $imgCache);
		$this->_setUploadDir( $uploadDir );
		$this->_setUploadUrl( $uploadUrl );
	}
	
	/**
	 *
	 * @param fImgData $imgData
	 * @return  fImgData
	 */
	public function deliveryImage( fImgData $imgData ) {
		$result = $this->_deliveryFromCache( $imgData );
		//$result = false;
		if( $result === false )
			$result = $this->_deliveryFromLocal( $imgData );
		if( $result === false )
			$result = $this->_deliveryFromRemote( $imgData );
		
		return $result;
	}
	
	private function _deliveryFromCache( fImgData $imgData ) {
		
		$cacheInfo = $this->_getImgCache()->getCacheInfo( $imgData->new->url );
		
		if( $cacheInfo == null ) return false;
		
		$imgData->new->path = $this->_getUploadDirPath( $imgData->new->filename );
		$cacheValidity = $this->_checkCacheValidity( $imgData, $cacheInfo );
		if( $cacheValidity === false ) return false;
		
		$imgData->ready = true;
		
		return $imgData;
	}
	
	private function _checkCacheValidity( fImgData $imgData, $cacheInfo ) {
		if( $cacheInfo->valid == true ) return true;
		
		if( !file_exists( $cacheInfo->pathOld) ) {
			$this->_getImgCache()->deleteCacheInfo( $imgData->new->url );
			$this->_getFileSystem()->deleteFile( $imgData->new->path );
			return false;
		}
		$newTS = $cacheInfo->timestamp;
		$oldTS = filemtime( $cacheInfo->pathOld );
		if( $newTS > $oldTS ) {
			$this->_getImgCache()->touchCachedFile( $imgData->new->url );
			return true;
		} else {
			$this->_getImgCache()->deleteCacheInfo( $imgData->new->url );
			$this->_getFileSystem()->deleteFile( $imgData->new->path );			
			return false;
		}
	} 
	
	private function _deliveryFromLocal( fImgData $imgData ) {
		$path = $this->_getImgPredictor()->predictPath( $imgData->old->url );
		
		if( $path != null ) {
			$imgData->old->path = $path;
			if ($this->_doesntHasAlphaLayer($path) && false ) {
				$imgData->new->filename = $this->_getImgNamer()->renameToJpg( $imgData->new->filename );
				$imgData->new->url = $this->_getImgNamer()->renameToJpg( $imgData->new->url );
			}
			$imgData->new->path = $this->_getUploadDirPath( $imgData->new->filename );
			$imgData->ready = false;
			
			return $imgData;
		} else {
			return false;
		}
	}	
	
	private function _doesntHasAlphaLayer( $path ) {
		if( file_exists( $path )) {
			$pathInfo = pathInfo($path);
			
			if( $pathInfo['extension'] != 'png') {
				return false;
			}
			
			$firstChars = $this->_getFileSystem()->openFile($path)->read(26);//->pointerTo(25)->read(1);
			//var_dump($firstChars);
			$char = $firstChars[25];
			$pngType = (ord($char));
		//	var_dump($pngType);
		}
		if( $pngType == 6 ) {
			return false;
		} else {
			return true;
		}
	}
	
	private function _deliveryFromRemote( fImgData $imgData ) {

		$remoteFilename = $this->_getImgNamer()->getRemoteImageName( $imgData->old->url );
		$remotePath = $this->_getUploadDirPath('remote/' . $remoteFilename);
		$remoteUrl = $this->_getUploadUrlPath('remote/' . $remoteFilename);
		
		$remoteFileCacheInfo = $this->_getImgCache()
										->getRemoteCacheInfo($imgData->old->url);
										//->getCacheInfo( $remotePath);
	
		if( $remoteFileCacheInfo != null && $remoteCacheInfo->valid == false ) {
		
			$remoteFileCacheInfo = null;
			$this->_getImgCache()->deleteRemoteCacheInfo( $remoteUrl );
			$this->_getFileSystem()->deleteFile( $remotePath );
		}
			
		if( $remoteFileCacheInfo == null ) {
	
			$this->_getImgDownloader()->downloadImage($imgData->old->url, $remotePath );
			if( file_exists( $remotePath) ) {
				$this->_getImgCache()->addCachedFileRemote($remoteUrl, $remotePath, $imgData->old->url);
				//$this->_getImgCache()->addCachedFile($urlNew, $urlOld, $pathNew, $pathOld, $remote)
			}
		}
		$imgData->new->path = $this->_getUploadDirPath( $imgData->new->filename );
		$imgData->old->url = $remoteUrl;
		$imgData->old->path = $remotePath;
		$imgData->ready = false;
		$imgData->remote = true;

		return $imgData;
	}

	
	
/*----------------------------------------------------------------------------*/
/* SETTERS AND GETTERS
/*----------------------------------------------------------------------------*/
	private function _getUploadDirPath( $path ) {
		return $this->_getUploadDir() . $path;
	}
	
	private function _getUploadUrlPath ( $path ) {
		return $this->_getUploadUrl() .'/'. $path;
	}
		
	
	private function _getUploadUrl() {
		return $this->_uploadUrl;
	}
	
	private function _setUploadUrl( $uploadUrl ) { 
		$this->_uploadUrl = $uploadUrl;
	}
	private function _getImgDownloader() {
		if( $this->_imgDownloader == null ) {
			$this->_imgDownloader = new blImgDownloader( $this->_getFileSystem(), $this->_getInputStream() );
		}
		
		return $this->_imgDownloader;
	}
	
	private function _getImgNamer() { 
		if( $this->_imgNamer == null ) { 
			$this->_imgNamer = new fImgNamer();
		}
		
		return $this->_imgNamer;
	}
	
	private function _setUploadDir( $uploadDir ) {
		$this->_uploadDir = $uploadDir;
	}
	
	private function _getUploadDir() {
		return $this->_uploadDir;
	}
	
	/**
	 * @return fImgPathPredictor
	 */
	private function _getImgPredictor() {
		if( $this->_imgPredictor == null ) {
			$this->_imgPredictor = new fImgPathPredictor();
		}
		
		return $this->_imgPredictor;
	}
	
	private function _setImgCache( blImgCache $imgCache ) {
		$this->_imgCache = $imgCache;
	}
	
	/**
	 * 
	 * @return blImgCache
	 */
	private function _getImgCache(){
		return $this->_imgCache;
	}
	private function _setFileSystem( blFileSystem $fileSystem ) {
		$this->_fileSystem = $fileSystem;
	}
	
	/**
	 * @return blFileSystem
	 */
	private function _getFileSystem() { 
		return $this->_fileSystem;
	}
	
	private function _setInputStream( blInputStreamAdapteour $inputStream ) {
		$this->_inputStream = $inputStream;
	}
	
	/**
	 * @return blInputStreamAdapteour
	 */
	private function _getInputStream() {
		return $this->_inputStream;
	}
}


class fImgNamer {
	private $_defaultUrl = null;
	private $_temporaryPathInfo = null;
	
	public function __construct( $defaultUrl = null ) {
		$this->_setDefaultUrl( $defaultUrl ); 
	}
	public function getNewImageName( $oldUrl, $width, $height = false, $crop = false, $remote = false) {
		$newUrl =  '';
		
		$partRemote = ( $remote ) ? 'remote/' : '';
		$partWidth = '-'.$width;
		$partHeight = ( $height ) ? '-'.$height : '';
		$partCrop =   ( $crop )   ? '-c' : '';
		
		//$newUrl .= $this->_getDefaultUrl() .'/';
		$newUrl .= $partRemote;
		$newUrl .= $this->_getUrlHash( $oldUrl ) . '_' ;
		$newUrl .= $this->_getImgName( $oldUrl );
		$newUrl .= $partWidth;
		$newUrl .= $partHeight;
		$newUrl .= $partCrop;
		$newUrl .= $this->_getImgExtension();
		
		return $newUrl;
	}
	public function renameToJpg( $path ) {
		$pathInfo = ( pathinfo($path));
		//var_dump( $pathInfo['dirname'] == '.');
		( $pathInfo['dirname'] == '.' ) ? $dirname = '' : $dirname = $pathInfo['dirname'] .'/';
		$toReturn =$dirname . $pathInfo['filename'] . '.jpg';
		//var_dump($toReturn);
		return $toReturn;
	}
	public function getNewImageUrl( $oldUrl, $width, $height = false, $crop = false, $remote = false ) {
		/**
		 * http://defaulturl(freshizer)/[remote]/$oldUrlHash_imgFilename-width[-height][-c(rop)].ext
		 */
		$newUrl =  '';
		
		$partRemote = ( $remote ) ? 'remote/' : '';
		$partWidth = '-'.$width;
		$partHeight = ( $height ) ? '-'.$height : '';
		$partCrop =   ( $crop )   ? '-c' : '';
		
		$newUrl .= $this->_getDefaultUrl() .'/';
		$newUrl .= $partRemote;
		$newUrl .= $this->_getUrlHash( $oldUrl ) . '_' ;
		$newUrl .= $this->_getImgName( $oldUrl );
		$newUrl .= $partWidth;
		$newUrl .= $partHeight;
		$newUrl .= $partCrop;
		$newUrl .= $this->_getImgExtension();
		
		
		return $newUrl;
 	}
 	
 	public function getRemoteImageName( $url ) {
 		$pathInfo = pathinfo( $url );
 		$newName = '';
 		$newName .= $this->_getUrlHash( $url );
 		$newName .= '-'.$pathInfo['filename'].'.'.$pathInfo['extension'];
 		
 		return $newName;
 	}
 	
 	private function _getImgExtension() {
 		$pathInfo = $this->_getTemporaryPathInfo();
 		return '.'.$pathInfo['extension'];
 	}
 	
 	private function _getImgName( $oldUrl ) {
 		$pathInfo = pathinfo( $oldUrl );
 		$this->_setTemporaryPathInfo( $pathInfo );
 		return $pathInfo['filename'];
 	}
 	
 	private function _setTemporaryPathInfo( $pathInfo ) {
 		$this->_temporaryPathInfo = $pathInfo;
 	}
 	
 	private function _getTemporaryPathInfo() {
 		return $this->_temporaryPathInfo;
 	}
 	
 	private function _getUrlHash( $url ) {
 		return md5($url);
 	}
	
	private function _setDefaultUrl( $defaultUrl ) {
		$this->_defaultUrl = $defaultUrl;
	}
	
	private function _getDefaultUrl() {
		return $this->_defaultUrl;
	}
}


interface fIImgPathPredictor {
	public function predictPath( $url );
	
	/*private function _predictionJunction();
	private function _predictUploads();
	private function _predictThemes();
	private function _predictPlugins();*/
}

class fAImgPathPredictor implements fIImgPathPredictor { 
	public function predictPath( $url ) {}
	
	protected function _predictUploads() {}
	protected function _predictThemes() {}
	protected function _predictPlugins() {}
}


class fImgPathPredictor {
	
	/**
	 * 
	 * @var fIImgPathPredictor
	 */
	private $_predictor = null;
	
	public function predictPath( $url ) {
		return $this->_getPredictor()->predictPath( $url );
	}
	
	
	private function _initializePredictor() {
		global $blog_id;
		
		if( is_multisite() && $blog_id != 1) { 
			$this->_setPredictor( new fImgPathPredictor_Multisite() );
		} else {
			$this->_setPredictor( new fImgPathPredictor_Single() );
		}
	}
	
	private function _setPredictor( fIImgPathPredictor $predictor) {
		$this->_predictor = $predictor;
	}
	
	/**
	 * @return fIImgPathPredictor
	 */
	private function _getPredictor() {
		if( $this->_predictor == null ) {
			$this->_initializePredictor();
		}
		
		return $this->_predictor;
	}
}
class fImgPathPredictor_Multisite extends fAImgPathPredictor implements fIImgPathPredictor {
	private $_imgUrl = null;
	private $_predictedPath = null;

	public function predictPath( $url ) {
		$this->_setImgUrl( $url );
		$this->_predictionJunction();

		return $this->_getPredictedPath();
	}

	protected function _predictionJunction() {
		//echo $this->_getImgUrl().'xxxx';
		//return;
		$uploadDir = wp_upload_dir();

		if( strpos( $this->_getImgUrl(), $uploadDir['baseurl']) !== false ) {
			$this->_predictUploads();
		} else if ( strpos( $this->_getImgUrl(), 'wp-content/themes') !== false ) {
			$this->_predictThemes();
		} else if ( strpos( $this->_getImgUrl(), 'wp-content/themes') !== false ) {
			$this->_predictPlugins();
		}

	}

	protected function _predictUploads() {
		$uploadDir = wp_upload_dir();
		$uploadSubpath = str_replace( $uploadDir['baseurl'],'', $this->_getImgUrl());

		$newRelPath = $uploadDir['basedir'].$uploadSubpath;

		if( file_exists( $newRelPath) ) {
			$this->_setPredictedPath( $newRelPath );
		}


	}
	protected function _predictThemes() {
		$splitedUrl = explode('themes/', $this->_getImgUrl() ); //explode() $this->_getImgUrl();
		$splitedPath = explode('themes/', get_template_directory() );
		$newRelPath = $splitedPath[0].'themes/'.$splitedUrl[1];

		if( file_exists( $newRelPath )) {
			$this->_setPredictedPath( $newRelPath );
		}
	}
	protected function _predictPlugins() {
		$imgPluginDirSplitted = explode('wp-content/plugins', $this->_getImgUrl() );
		$imgAfterPluginDir = $imgPluginDirSplited[1];

		$pluginDir = WP_PLUGIN_DIR;
		$newRelPath = $pluginDir . $imgAfterPluginDir;

		if( file_exists( $newRelPath ) ) {
			$this->_setPredictedPath( $newRelPath );
		}
                
               

	}


	private function _getPredictedPath() {
		return $this->_predictedPath;
	}

	private function _setPredictedPath( $predictedPath ) {
		$this->_predictedPath = $predictedPath;
	}

	private function _setImgUrl( $imgUrl ) {
		$this->_imgUrl = $imgUrl;
	}

	private function _getImgUrl() {
		return $this->_imgUrl;
	}
}

class fImgPathPredictor_Single extends fAImgPathPredictor implements fIImgPathPredictor {
	private $_imgUrl = null;
	private $_predictedPath = null;
	
	public function predictPath( $url ) {
		$this->_setImgUrl( $url );
		$this->_predictionJunction();
		return $this->_getPredictedPath();
	}
	
	protected function _predictionJunction() {
		if( strpos( $this->_getImgUrl(), 'wp-content/uploads') !== false ) {
			$this->_predictUploads();
		} else if ( strpos( $this->_getImgUrl(), 'wp-content/themes') !== false ) {
			$this->_predictThemes();
		} else if ( strpos( $this->_getImgUrl(), 'wp-content/themes') !== false ) {
			$this->_predictPlugins();
		}		
		
	}
	
	protected function _predictUploads() {
		$imgUploadDirSplited = explode('wp-content/uploads', $this->_getImgUrl() );
		$imgAfterUploadDir = $imgUploadDirSplited[1];
		$wpUploadDir = wp_upload_dir();
		$baseDir = $wpUploadDir['basedir'];
		
		$newRelPath = $baseDir . $imgAfterUploadDir;
		
		if( file_exists( $newRelPath) ) {
			$this->_setPredictedPath( $newRelPath );
		}
		
		
	}
	protected function _predictThemes() {
		$imgThemeDirSplited = explode('wp-content/themes', $this->_getImgUrl() );
		$imgAfterThemeDir = $imgThemeDirSplited[1];
		
		$currentThemeDirSplited = explode( 'wp-content/themes', get_template_directory());
		$currentThemeFolder = $currentThemeDirSplited[0];
		
		$newRelPath = $currentThemeFolder . 'wp-content/themes' . $imgAfterThemeDir;
		
		if( file_exists( $newRelPath )) {
			$this->_setPredictedPath( $newRelPath );
		}
	}
	protected function _predictPlugins() {
		$imgPluginDirSplitted = explode('wp-content/plugins', $this->_getImgUrl() ); 
		$imgAfterPluginDir = $imgPluginDirSplited[1];
		
		$pluginDir = WP_PLUGIN_DIR;
		$newRelPath = $pluginDir . $imgAfterPluginDir;
		
		if( file_exists( $newRelPath ) ) {
			$this->_setPredictedPath( $newRelPath );
		}

	}
	
	
	private function _getPredictedPath() {
		return $this->_predictedPath;
	}
	
	private function _setPredictedPath( $predictedPath ) {
		$this->_predictedPath = $predictedPath;
	}
	
	private function _setImgUrl( $imgUrl ) {
		$this->_imgUrl = $imgUrl;
	}
	
	private function _getImgUrl() {
		return $this->_imgUrl;
	}
}


class fImgResizer {
	
	/**
	 * 
	 * @var blFileSystem
	 */
	private $_fileSystem = null;
	
	/**
	 * @var fImgResizerCalculator
	 */
	private $_imgResizerCalculator = null;
	
	private $_imgHasAlfaChannel = null;
	
	public function __construct( blFileSystem $fileSystem ) {
		$this->_setFileSystem($fileSystem);
	}
	
	public function resize( fImgData $imgData ) {// stdClass $pathInfo, stdClass $imgInfo ) {
		//var_dump($imgData);
		$imageOld = $this->_openImage( $imgData->old->path );
		$orig = $this->_getImgDimensions( $imgData->old->path );
		
	
		$newDimensions = $this->_getImgResizerCalculator()->calculateNewDimensions( $orig->width, 
																					$orig->height, 
																					$imgData->new->width, 
																					$imgData->new->height, 
																					$imgData->new->crop );
		
		$imageNew = $this->_createImage( $newDimensions['dst']['w'],$newDimensions['dst']['h']);
		
		
		imagecopyresampled($imageNew, $imageOld, $newDimensions['dst']['x'],
												 $newDimensions['dst']['y'],
												 $newDimensions['src']['x'],
												 $newDimensions['src']['y'],
												 $newDimensions['dst']['w'],
												 $newDimensions['dst']['h'],
												 $newDimensions['src']['w'],
												 $newDimensions['src']['h']);
                if(function_exists('imageantialias') ) {
                    imageantialias( $imageNew, true );
                }
		$pathInfo = pathinfo($imgData->old->path);
		
        if ( $pathInfo['extension'] == 'png' && function_exists('imageistruecolor') && !imageistruecolor( $imageOld ) ) {
                imagetruecolortopalette( $imageNew, false, imagecolorstotal( $imageOld ) );
        }
		$this->_getFileSystem()->saveImage( $imageNew, $imgData->new->path );
		
		imagedestroy($imageOld);
		imagedestroy($imageNew);
		$this->_imgHasAlfaChannel = null;
		$dimToReturn = array();
		
	}
	
	private function _openImage( $path ) {
		$imageString = $this->_getFileSystem()->openFile( $path )->readAllAndClose();
		$pathInfo = pathinfo($path);
		if( $pathInfo['extension'] == 'png' && ord($imageString[25]) == 6 ) 
			$this->_imgHasAlfaChannel = true;
		//return (ord(@file_get_contents($fn, NULL, NULL, 25, 1)) == 6);
		@ini_set( 'memory_limit', '256M' );
		$image = imagecreatefromstring( $imageString );
		return $image;
	}
	
	
	private function _getImgDimensions( $path ) {
		$dim = getimagesize( $path );
		$result = new stdClass();
		$result->width = $dim[0];
		$result->height = $dim[1];
		return $result;
	}
	private function _createImage ($width, $height) {
		$img = imagecreatetruecolor($width, $height);
		if ( is_resource($img) && $this->_imgHasAlfaChannel && function_exists('imagealphablending') && function_exists('imagesavealpha') ) {
			imagealphablending($img, false);
			imagesavealpha($img, true);
		}
		return $img;
	}	
	
/*----------------------------------------------------------------------------*/
/* SETTERS AND GETTERS
/*----------------------------------------------------------------------------*/
	private function _getImgResizerCalculator() {
		if( $this->_imgResizerCalculator == null ) { 
			$this->_imgResizerCalculator = new fImgResizerCalculator();
		}
		
		return $this->_imgResizerCalculator;
	}
	
	/**
	 * @return blFileSystem
	 */
	private function _getFileSystem() {
		return $this->_fileSystem;
	}
	
	private function _setFileSystem( $fileSystem ) {
		$this->_fileSystem = $fileSystem;
	}
}


class fImgResizerCalculator {
	public function calculateNewDimensions($orig_w, $orig_h, $dest_w, $dest_h, $crop = false) {
		
		if ( $crop ) {
			
			// crop the largest possible portion of the original image that we can size to $dest_w x $dest_h
			$aspect_ratio = $orig_w / $orig_h;
			$new_w =$dest_w;// min($dest_w, $orig_w);
			$new_h =$dest_h;// min($dest_h, $orig_h);
	
			if ( !$new_w ) {
				$new_w = intval($new_h * $aspect_ratio);
			}
	
			if ( !$new_h ) {
				$new_h = intval($new_w / $aspect_ratio);
			}
			
			$size_ratio = max($new_w / $orig_w, $new_h / $orig_h);
	
			$crop_w = round($new_w / $size_ratio);
			$crop_h = round($new_h / $size_ratio);
	
			$s_x = floor( ($orig_w - $crop_w) / 2 );
			$s_y = floor( ($orig_h - $crop_h) / 2 );
		} else {
			// don't crop, just resize using $dest_w x $dest_h as a maximum bounding box
			
			$crop_w = $orig_w;
			$crop_h = $orig_h;
	
			$s_x = 0;
			$s_y = 0;
	
	
			list( $new_w, $new_h ) = $this->constrainNewDimensions( $orig_w, $orig_h, $dest_w, $dest_h );
		}
		$to_return = array();
		$to_return['src']['x'] = (int)$s_x;
		$to_return['src']['y'] = (int)$s_y;
		$to_return['src']['w'] = (int)$crop_w;
		$to_return['src']['h'] = (int)$crop_h;
	
		$to_return['dst']['x'] = 0;
		$to_return['dst']['y'] = 0;
		$to_return['dst']['w'] = (int)$new_w;
		$to_return['dst']['h'] = (int)$new_h;
	
		return $to_return;
	}
	
	/**
	 * This function has been take over from wordpress core. It calculate the best proportion to uncropped image
	 */
	public function constrainNewDimensions( $current_width, $current_height, $max_width=0, $max_height=0 ) {
		
		if ( !$max_width and !$max_height )
			return array( $current_width, $current_height );
		
	
		$width_ratio = $height_ratio = 1.0;
		$did_width = $did_height = false;
	
		if ( $max_width > 0 && $current_width > 0 )
		{
			$width_ratio = $max_width / $current_width;
			$did_width = true;
		}
	
		if ( $max_height > 0 && $current_height > 0 )
		{
			$height_ratio = $max_height / $current_height;
			$did_height = true;
		}
	
		// Calculate the larger/smaller ratios
		$smaller_ratio = min( $width_ratio, $height_ratio );
		$larger_ratio  = max( $width_ratio, $height_ratio );
		
		if ( intval( $current_width * $larger_ratio ) > $max_width || intval( $current_height * $larger_ratio ) > $max_height )
			// The larger ratio is too big. It would result in an overflow.
			$ratio = $smaller_ratio;
		else
			// The larger ratio fits, and is likely to be a more "snug" fit.
			$ratio = $larger_ratio;
		//echo $current_width;
		if( $max_width > $current_width && $max_height == 0 ) {
			$ratio = $larger_ratio;	
		}
		
		$w = intval( $current_width  * $ratio );
		$h = intval( $current_height * $ratio );
		
		// Sometimes, due to rounding, we'll end up with a result like this: 465x700 in a 177x177 box is 117x176... a pixel short
		// We also have issues with recursive calls resulting in an ever-changing result. Constraining to the result of a constraint should yield the original result.
		// Thus we look for dimensions that are one pixel shy of the max value and bump them up
		if ( $did_width && $w == $max_width - 1 )
			$w = $max_width; // Round it up
		if ( $did_height && $h == $max_height - 1 )
			$h = $max_height; // Round it up
	
		return array( $w, $h );
	}
}

class fImg {
	/**
	 * @var fImg
	 */
	private static $_instance = null;

	/**
	 * @var fImgNamer
	 */
	private $_imgNamer = null;
	
	/**
	 * @var blFileSystem
	 */
	private $_fileSystem = null;

	/**
	 * @var blImgCache
	 */
	private $_imgCache = null;
	
	/**
	 * @var fImgDeliverer
	 */
	private $_imgDeliverer = null;
	
	/**
	 * @var blInputStreamAdapteour
	 */
	private $_inputStream = null;
	
	/**
	 * @var fImgResizer
	 */
	private $_imgResizer = null;
	
	
	private $_defaultUrl = null;
	
	private $_defaultDir = null;
	
/*----------------------------------------------------------------------------*/
/* PUBLIC FUNCTIONS
/*----------------------------------------------------------------------------*/
		
	public function __construct() {
		$this->_createDefaultUrlAndDir();
		$this->_setImgCache( new blImgCache( $this->_getFileSystem(), $this->_getDefaultDir() ) );
		$this->_setImgDeliverer( new fImgDeliverer( $this->_getFileSystem(), $this->_getInputStream(), $this->_getImgCache(), $this->_getDefaultDir(), $this->_getDefaultUrl() ) );
		$this->_setImgResizer( new fImgResizer( $this->_getFileSystem() ) );
	}
	
	public function getInstance() {
		if( self::$_instance == null ) {
			self::$_instance = new fImg();
		}
		
		return self::$_instance;
	}

	
	public static function ResizeC( $url, $width, $height = false, $crop = false, $returnImgSize = false ) {
		$width = (int)$width;
		$height = (int)$height;
		
		return self::getInstance()->_resize($url, $width, $height, $crop, $returnImgSize);
	}
	

	public static function resize( $url, $width, $height = false, $crop = false, $returnImgSize = false ) {
		$width = (int)$width;
		$height = (int)$height;
		
		return self::getInstance()->_resize($url, $width, $height, $crop, $returnImgSize = false);
	}	
	
	public static function getImgSize( $url ) {
		return self::getInstance()->_getImgSize( $url );
	}
	
	private function _getImgSize( $url ) {
		$imgData = $this->_getImgData($url, 0, false, false);
		$imgData = $this->_getImgDeliverer()->deliveryImage($imgData);
		return $imgData;
	}
	
	private function _resize( $url, $width, $height = false, $crop = false, $returnImgSize = false ) {
		if( empty($url) ) return null;
		
		$imgData = $this->_getImgData($url, $width, $height, $crop);
		$imgData = $this->_getImgDeliverer()->deliveryImage( $imgData );
		
		if( $imgData == false ) {
			echo 'Image :'.$url.' cannot be opened';
			return false; 
		}
		
		if( $imgData->ready == false ) {
			
			$this->_getImgResizer()->resize( $imgData );
			$this->_getImgCache()
					->addCachedFile( $imgData->new->url, $imgData->old->url, $imgData->new->path, $imgData->old->path, $imgData->remote);
		}
		if( $returnImgSize ) {
			$size = getimagesize($imgData->new->path);
			
			$toReturn = array();
			$toReturn['width'] = $size[0];
			$toReturn['height'] = $size[1];
			$toReturn['url'] = $imgData->new->url;
			
			return $toReturn;
		} else {
			return $imgData->new->url;
		}
		
	}	
/*----------------------------------------------------------------------------*/
/* PRIVATE FUNCTIONS
/*----------------------------------------------------------------------------*/
	/**
	 * @return fImgData
	 */
	private function _getImgData( $url, $width, $height, $crop ) {
		$imgData = $this->_getImageInfoAsClass($url, $width, $height, $crop);
		$imgData->new->url = $this->_getImgNamer()->getNewImageUrl( $url, $width, $height, $crop);
		$imgData->new->filename = $this->_getImgNamer()->getNewImageName($url, $width, $height, $crop);
	
		return $imgData;
	}	
	
	/**
	 * 
	 * @return fImgData
	 */
	private function _getImageInfoAsClass( $url, $width, $height,$crop) {
		$imgData = new fImgData();
		$imgData->old->url = $url;
		$imgData->new->width = (int)$width;
		$imgData->new->height = (int)$height;
		$imgData->new->crop = $crop;

		return $imgData;
	}	
	
	private function _createDefaultUrlAndDir() {
		$wpUploadDir = wp_upload_dir();
		$this->_setDefaultUrl( $wpUploadDir['baseurl'].'/freshizer');
		$this->_setDefaultDir( $wpUploadDir['basedir'].'/freshizer/');
	}
		
/*----------------------------------------------------------------------------*/
/* SETTERS AND GETTERS
/*----------------------------------------------------------------------------*/
	private function _setImgResizer( fImgResizer $imgResizer ) {
		$this->_imgResizer = $imgResizer;
	}
	/**
	 * @return fImgResizer
	 */
	private function _getImgResizer() {
		return $this->_imgResizer;
	}
	
	private function _setImgDeliverer( fImgDeliverer $imgDeliverer ) {
		$this->_imgDeliverer = $imgDeliverer;
	}
	
	/**
	 * @return fImgDeliverer
	 */
	private function _getImgDeliverer() {
		return $this->_imgDeliverer;
	}
	
	private function _setInputStream( blInputStreamAdapteour $inputStream ) {
		$this->_inputStream = $inputStream;
	}
	
	/**
	 * 
	 * @return blInputStreamAdapteour
	 */
	private function _getInputStream() {
		if( $this->_inputStream == null ) {
			$this->_inputStream =  new blInputStreamAdapteour() ;
		}
		return $this->_inputStream;
	}
	
	private function _setDefaultUrl( $defaultUrl ) {
		$this->_defaultUrl = $defaultUrl;
	}
	private function _getDefaultUrl() {
		return $this->_defaultUrl;
	}
	
	private function _getImgNamer() {
		if( $this->_imgNamer == null ) {
			$this->_imgNamer = new fImgNamer($this->_getDefaultUrl());
		}
		return $this->_imgNamer;
	}
	
	private function _getImgCache() {
		return $this->_imgCache;
	}
	
	private function _setImgCache( blImgCache $imgCache ) {
		$this->_imgCache = $imgCache;
	}
	
	private function _getFileSystem() {
		if( $this->_fileSystem == null ) {
			$this->_fileSystem = new blFileSystem();
		}
		return $this->_fileSystem;
	}
	
	private function _setDefaultDir( $defaultDir) { 
		$this->_defaultDir = $defaultDir;
	}
	
	private function _getDefaultDir() { 
		return $this->_defaultDir;
	}
	
	public static function DeleteCache() {
		
	}
}



