function DodjiPhotoModule() {
	var MAX_PHOTO_SIZE = 4194304,
		MIN_PHOTO_WIDTH = 600,
		MIN_PHOTO_HEIGHT = 400,
		MAX_PHOTO_WIDTH = 6000,
		MAX_PHOTO_HEIGHT = 6000,
		WIDTH_RATIO = 3,
		HEIGHT_RATIO = 2;

	var $_addPhotoBlock = {},
		$_resizeImage = {},
		$_photoBlocks = [],
		_photoCount = 0,
		_options = {
			maxCount: 0
		},
		self,
		ias;

	var classes = {
		resizeImage: 'js-photo-resize__image',
		thumbImage: 'thumb-img',
		photoSizeInput: 'js-photo-size',
		deleteLink: 'js-delete',
		fileInput: 'js-file-input',
		deletePhotoInput: 'js-delete-photo',
		oldPhotoIdInput: 'js-old-photo-id'
	};

	/**
	 * Возможные загружаемые файлы
	 * @type Array
	 */
	var avaibleExtensions = [
		"jpeg",
		"jpg",
		"png",
		"gif"
	];
	var avaiblePhotoFormats = [
		"jpg",
		"png",
		"gif"
	];

	var _setBlockEvents = function($block) {
		$block.on('click', '.js-file-add-button', function() {
			$block.find('.' + classes.fileInput).trigger('click');
		});

		$block.on('change', '.' + classes.fileInput, {
			'block': $block
		}, _fileSelectEvent);

		$block.on('click', '.js-delete', {
			'block': $block
		}, function(e) {
			self.clearImage(e.data.block);
		});
	};

	/**
	 * Проверка на расширение
	 * @param {string} filename
	 * @returns {Boolean}
	 */
	var _fileCheckExtension = function(filename) {
		var ext = filename.split(".");
		ext = ext[ext.length - 1].toLowerCase();
		if (!in_array(ext, avaibleExtensions)) {
			return false;
		}
		return true;
	};

	var _fileSelectEvent = function(e) {
		var files = e.target.files;
		for (var i = 0, file; file = files[i]; i++) {
			if (!file.type.match('image.*')) {
				continue;
			}

			if (!_checkFileSize(file.size)) {
				self.clearImage(e.data.block);
				_setError('Размер файла не должен превышать 4 МБ', e.data.block);
				continue;
			}
			if (!_fileCheckExtension(file.name)) {
				self.clearImage(e.data.block);
				_setError('Неверный формат изображения. Поддерживаемые форматы: ' + avaiblePhotoFormats.join(", "), e.data.block);
				continue;
			}

			_readPhotoForPreview(file, e.data.block);
		}
	};

	var _readPhotoForPreview = function(f, $block) {
		var reader = new FileReader();

		reader.onload = (function() {
			return function(e) {
				var image = new Image();
				image.src = e.target.result;
				_setError('', $block);

				image.onload = function() {
					if (!_checkMinImageResolution(image) || !_checkMaxImageResolution(image)) {
						$_resizeImage.imgAreaSelect({
							onSelectChange: function() {
								return true;
							},
							parent: '.all_page'
						});
						$_resizeImage
							.hide()
							.imgAreaSelect({
								remove: true,
								parent: '.all_page'
							})
							.removeAttr('src');

						self.clearImage($block);
						if (!_checkMinImageResolution(image)) {
							_setError(t('Размер изображения должен быть не меньше {{0}}х{{1}} пикселей.', [MIN_PHOTO_WIDTH, MIN_PHOTO_HEIGHT]), $block);
						} else if (!_checkMaxImageResolution(image)) {
							_setError(t('Размер изображения должен быть не больше {{0}}х{{1}} пикселей.', [MAX_PHOTO_WIDTH, MAX_PHOTO_HEIGHT]), $block);
						}
						return false;
					}

					$_resizeImage.attr('src', e.target.result).show();
					var $img = $('<img class="' + classes.thumbImage + '">')
						.attr('src', e.target.result)
						.css('background', '#fafafa');
					$block.find('.' + _options.fileWrapperClass).html('').append($img);

					ias = $_resizeImage.imgAreaSelect({
						handles: true,
						aspectRatio: _options.widthRatio + ":" + _options.heightRatio,
						persistent: true,
						parent: '.all_page',
						onSelectChange: function(img, coordinates) {
							_setPreview(coordinates, $block);
						},
						instance: true
					});

					var ratio = _options.widthRatio / _options.heightRatio;
					var w_need = _options.minWidth * (100 / $_resizeImage[0].naturalWidth) / 100;
					var min_w_selection = $_resizeImage.width() * w_need;
					var min_h_selection = min_w_selection / ratio;
					var max_w_selection = Math.min($_resizeImage.width(), $_resizeImage.height() * ratio);
					var max_h_selection = Math.min($_resizeImage.height(), $_resizeImage.width() / ratio);

					if ($_resizeImage[0].naturalWidth == MIN_PHOTO_WIDTH) {
						min_w_selection = max_w_selection;
					}
					if ($_resizeImage[0].naturalHeight == MIN_PHOTO_HEIGHT) {
						min_h_selection = max_h_selection;
					}

					ias.setSelection(0, 0, max_w_selection, max_h_selection);
					ias.setOptions({
						show: true,
						minWidth: min_w_selection,
						minHeight: min_h_selection
					});
					ias.update();
					_setPreview(ias.getSelection(), $block);
					self.markAsNotDelete($block);
					$_resizeImage.data('imageBlock', $block);
					$block.data('naturalSizes', {
						width: $_resizeImage[0].naturalWidth,
						height: $_resizeImage[0].naturalHeight
					});
				};
			};
		})(f);

		reader.readAsDataURL(f);
	};

	var _setError = function(text, $block) {

		var errorBlock = $(".js-prd-save-field-error.prd-save-step__field-error.firstPhoto");
		if ($('*').is(errorBlock) === false) {
			errorBlock = $($block).closest('.js-add-photo').find('.js-add-photo_error');
		}
		errorBlock.text(text);
	};

	var _checkFileSize = function(size) {
		return size <= MAX_PHOTO_SIZE;
	};

	var _checkMinImageResolution = function(img) {
		return !(img.width < MIN_PHOTO_WIDTH || img.height < MIN_PHOTO_HEIGHT);
	};

	var _checkMaxImageResolution = function(img) {
		return !(img.width > MAX_PHOTO_WIDTH || img.height > MAX_PHOTO_HEIGHT);
	};

	var _setPreview = function(coordinates, $block) {
		var rx = $($block).find('.' + _options.fileWrapperClass).width() / coordinates.width;
		var ry = $($block).find('.' + _options.fileWrapperClass).height() / coordinates.height;

		var imageMaxWidth = $_resizeImage.width();
		var imageMaxHeight = $_resizeImage.height();
		var xPercent = coordinates.x1 / imageMaxWidth;
		var yPercent = coordinates.y1 / imageMaxHeight;
		var x2Percent = coordinates.x2 / imageMaxWidth;
		var y2Percent = coordinates.y2 / imageMaxHeight;

		$block.find('.' + classes.thumbImage).css({
			width: Math.round(rx * imageMaxWidth) + 'px',
			height: Math.round(ry * imageMaxHeight) + 'px',
			marginLeft: '-' + Math.round(rx * coordinates.x1) + 'px',
			marginTop: '-' + Math.round(ry * coordinates.y1) + 'px'
		});

		var inputCoordinates = {
			'x': xPercent,
			'y': yPercent,
			'w': Math.abs(xPercent - x2Percent),
			'h': Math.abs(yPercent - y2Percent),
			'x1': coordinates.x1,
			'y1': coordinates.y1,
			'x2': coordinates.x2,
			'y2': coordinates.y2,
			'minW': imageMaxWidth,
			'minH': imageMaxHeight,
      'ratio': _options.widthRatio + ":" + _options.heightRatio
		};

		$block.find('.' + classes.photoSizeInput).val(JSON.stringify(inputCoordinates));
		$block.data('sizes', inputCoordinates);
	};

	var _setStartImages = function() {
		if (typeof _options == 'undefined' || !_options.hasOwnProperty('photos') || Object.keys(_options.photos).length == 0) {
			self.addRow();
		} else {
			for (var i = 0; i < _options.photos.length; i++) {
				self.addPhoto(_options.photos[i]);
			}

			var emptyBlocks = 3 - _options.photos.length % 3;

			for (i = 0; i < emptyBlocks; i++) {
				self.addPhoto(0);
			}
		}

		_checkExcessBlocks();
	};

	var _hideResizeBlock = function() {
		$_resizeImage.removeAttr('src').hide();
		$_resizeImage.imgAreaSelect({
			remove: true
		});
	};

	var _setVisibilityAddRowButton = function() {
		if (_photoCount >= _options.maxCount) {
			$(_options.selectorBlock).find('.js-add-photo-row-btn').hide();
		} else {
			$(_options.selectorBlock).find('.js-add-photo-row-btn').show();
		}
	};

	var _checkExcessBlocks = function() {
		for (var i = _options.maxCount; i < $_photoBlocks.length; i++) {
			$($_photoBlocks[i]).addClass('hidden');
			_hideResizeBlock();
		}

		for (i = 0; i < _options.maxCount; i++) {
			$($_photoBlocks[i]).removeClass('hidden');
		}
	};

	return {
		init: function(options) {
			self = this;
			_options = options;

			if (!_options.maxCount) {
				_options.maxCount = 3;
			}
			if (!_options.minWidth) {
				_options.minWidth = MIN_PHOTO_WIDTH;
			} else {
				MIN_PHOTO_WIDTH = _options.minWidth;
			}
			if (!_options.minHeight) {
				_options.minHeight = MIN_PHOTO_HEIGHT;
			} else {
				MIN_PHOTO_HEIGHT = _options.minHeight;
			}
			if (!_options.widthRatio) {
				_options.widthRatio = WIDTH_RATIO;
			}
			if (!_options.heightRatio) {
				_options.heightRatio = HEIGHT_RATIO;
			}

			$_addPhotoBlock = $(_options.selectorBlock).find('.js-add-photo');

			$_resizeImage = $(_options.selectorBlock).find('.' + classes.resizeImage);

			$(_options.selectorBlock).find('.js-add-photo-row-btn').on('click', self.addRow);
			_setStartImages();

			self.checkDocumentChanged();
		},
		addRow: function() {
			for (var i = 0; i < 3; i++) {
				self.addPhoto();
			}
			_hideResizeBlock();
		},
		addPhoto: function(photo) {
			if (_photoCount >= _options.maxCount && typeof photo == 'undefined') {
				return;
			}

			var photoBlockHtml = $_addPhotoBlock.find('.js-template-photo-block').html();
			var $photoBlock;

			$photoBlock = $(photoBlockHtml);
			$photoBlock.find('.' + classes.fileInput).attr('name', _options.fileInputName + (_options.maxCount > 1 ? '[]' : ''));
			$photoBlock.find('.' + classes.deletePhotoInput).attr('name', 'delete-photo[' + (photo ? photo.id : '') + ']');
			$photoBlock.find('.' + classes.photoSizeInput).attr('name', _options.fileInputName + '-size' + (_options.maxCount > 1 ? '[]' : ''));

			if (_photoCount == 0) {
				$photoBlock.find('.js-file-add-button').html($photoBlock.find('.js-file-add-button').data('firstText'));
				$photoBlock.find('.' + classes.deletePhotoInput).remove();
				$photoBlock.find('.' + classes.deleteLink).remove();
			}

			_setBlockEvents($photoBlock);

			if (typeof photo != 'undefined' && typeof photo == 'object') {
				$photoBlock.find('.' + classes.oldPhotoIdInput).val(photo.id).attr('name', 'old-photo' + (_options.maxCount > 1 ? '[]' : ''));
				$photoBlock.find('.' + _options.fileWrapperClass).css({
					'background': 'url(' + photo.value + ')',
					'background-size': '100%'
				});

				this.markAsNotDelete($photoBlock);
			}

			$_addPhotoBlock.find('.js-photo__block').append($photoBlock);
			$_photoBlocks[_photoCount] = $photoBlock;
			_photoCount += 1;

			_setVisibilityAddRowButton();
		},
		markAsDelete: function($block) {
			$block.find('.' + classes.deletePhotoInput).val(1);
			$block.find('.' + classes.deleteLink).addClass('hidden');
		},
		markAsNotDelete: function($block) {
			$block.find('.' + classes.deletePhotoInput).val(0);
			$block.find('.' + classes.deleteLink).removeClass('hidden');
		},
		clearImage: function($block) {
			$block.find('.' + classes.thumbImage).remove();
			$block.find('.' + _options.fileWrapperClass).removeAttr('style');
			$block.find('.' + classes.photoSizeInput).val('');
			$block.find('.' + classes.fileInput).val('');
			$block.data('sizes', null);
			$block.data('naturalSizes', null);
			if ($_resizeImage.data('imageBlock') == $block) {
				_hideResizeBlock();
			}

			self.markAsDelete($block);
		},
		hideResizeBlock: _hideResizeBlock,
		checkSubmitSize: function(e) {
			for (var i = 0; i < $_photoBlocks.length; i++) {
				var $photoBlock = $_photoBlocks[i];
				if ($photoBlock.find('.' + classes.fileInput).val().length) {
					var percentSizes = $photoBlock.data('sizes');
					var naturalSizes = $photoBlock.data('naturalSizes');

					if (Math.ceil(naturalSizes.width * percentSizes.w) < MIN_PHOTO_WIDTH || Math.ceil(naturalSizes.height * percentSizes.h) < MIN_PHOTO_HEIGHT) {
						e.preventDefault();
						_setError(t('Размер выделенного участка изображения {{0}} должен быть не меньше {{1}}х{{2}} пикселей.', [(i + 1), MIN_PHOTO_WIDTH, MIN_PHOTO_HEIGHT]), $photoBlock);
						return false;
					}
				}
			}
		},
		hasSelectedPhoto: function() {
			var oldPhotoVal = '';

			if ($_photoBlocks[0].find('.' + classes.oldPhotoIdInput).length) {
				oldPhotoVal = $_photoBlocks[0].find('.' + classes.oldPhotoIdInput).val().length
			}

			if (oldPhotoVal || $_photoBlocks[0].find('.' + classes.fileInput).val().length) {
				return true;
			}

			return false;
		},
		changeMaxPhoto: function(maxCount) {
			_options.maxCount = maxCount ^ 0;

			if (_options.maxCount == 0) {
				_options.maxCount = 3;
			}

			_checkExcessBlocks();
			_setVisibilityAddRowButton();
		},
		getPhotoSize: function() {
			var totalSize = 0;

			for (var i = 0; i < $_photoBlocks.length; i++) {
				var file = $($_photoBlocks[i]).find('.' + classes.fileInput)[0].files[0];
				if (typeof file != 'undefined') {
					totalSize += file.size || file.fileSize;
				}
			}

			return totalSize;
		},
		cancelModule: function() {
			for (var i = 0; i < $_photoBlocks.length; i++) {
				self.clearImage($_photoBlocks[i]);
			}
		},
		checkDocumentChanged: function() {
			var lastHeight = document.body.scrollHeight,
				newHeight;
			(function run() {
				newHeight = document.body.scrollHeight;
				if (lastHeight != newHeight)
					self.reDraw();
				lastHeight = newHeight;

				if (self.onElementHeightChangeTimer)
					clearTimeout(self.onElementHeightChangeTimer);

				self.onElementHeightChangeTimer = setTimeout(run, 200);
			})();
		},
		reDraw: function() {
			if (typeof ias != 'undefined') {
				ias.update();
			}
		}
	}
}