/*
*
* Copyright 2013 Entando S.r.l. (http://www.entando.com) All rights reserved.
*
* This file is part of Entando software.
* Entando is a free software;
* You can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) as published by the Free Software Foundation; version 2.
*
* See the file License for the specific language governing permissions
* and limitations under the License
*
*
*
* Copyright 2013 Entando S.r.l. (http://www.entando.com) All rights reserved.
*
*/
package com.agiletec.plugins.jpimagemap.aps.system.services.content.model.attribute;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jdom.Element;
import com.agiletec.aps.system.common.entity.model.attribute.AbstractComplexAttribute;
import com.agiletec.aps.system.common.entity.model.attribute.AttributeInterface;
import com.agiletec.aps.system.common.entity.model.attribute.DefaultJAXBAttribute;
import com.agiletec.aps.system.exception.ApsSystemException;
import com.agiletec.aps.system.ApsSystemUtils;
import com.agiletec.aps.system.common.entity.model.AttributeFieldError;
import com.agiletec.aps.system.common.entity.model.AttributeTracer;
import com.agiletec.plugins.jacms.aps.system.JacmsSystemConstants;
import com.agiletec.plugins.jacms.aps.system.services.content.model.extraAttribute.ImageAttribute;
import com.agiletec.plugins.jacms.aps.system.services.content.model.extraAttribute.JAXBLinkValue;
import com.agiletec.plugins.jacms.aps.system.services.content.model.extraAttribute.JAXBResourceValue;
import com.agiletec.plugins.jacms.aps.system.services.content.model.extraAttribute.LinkAttribute;
import com.agiletec.plugins.jacms.aps.system.services.content.model.extraAttribute.ResourceAttributeInterface;
import com.agiletec.plugins.jacms.aps.system.services.resource.IResourceManager;
import com.agiletec.plugins.jacms.aps.system.services.resource.model.ResourceInterface;
import com.agiletec.plugins.jpimagemap.aps.system.services.content.model.attribute.model.JAXBAreaValue;
import com.agiletec.plugins.jpimagemap.aps.system.services.content.model.attribute.model.JAXBImageMapValue;
import com.agiletec.plugins.jpimagemap.aps.system.services.content.model.attribute.util.LinkedArea;
import java.awt.Rectangle;
/**
* Rappresenta un informazione tipo ImageMap.
* @author E.Santoboni - G.Cocco
*/
public class ImageMapAttribute extends AbstractComplexAttribute implements ResourceAttributeInterface {
@Override
public void setRenderingLang(String langCode) {
super.setRenderingLang(langCode);
if (this.getImage() != null) {
this.getImage().setRenderingLang(langCode);
if (_areas.size() > 0) {
Iterator<LinkedArea> iteratorAreas = _areas.iterator();
while (iteratorAreas.hasNext()) {
LinkedArea linkedArea = (LinkedArea) iteratorAreas.next();
linkedArea.getLink().setRenderingLang(langCode);
}
}
}
}
@Override
public Object getAttributePrototype() {
ImageMapAttribute clone = (ImageMapAttribute) super.getAttributePrototype();
if (this.getImage() != null) {
clone.setImage((ImageAttribute)this.getImage().getAttributePrototype());
}
if (this.getPrototype() != null) {
clone.setPrototype((LinkedArea)this.getPrototype().clone());
}
return clone;
}
@Override
public List<AttributeInterface> getAttributes() {
List<AttributeInterface> attributes = new ArrayList<AttributeInterface>();
attributes.add(_image);
for(int i = 0; i < _areas.size(); i++ ){
attributes.add(((LinkedArea)_areas.get(i)).getLink());
}
return attributes;
}
@Override
public Object getRenderingAttributes() {
return this;
}
@Override
public void setComplexAttributeConfig(Element attributeElement, Map attrTypes) throws ApsSystemException {
_image = (ImageAttribute) ((ImageAttribute) attrTypes.get("Image")).getAttributePrototype();
_image.setAttributeConfig(attributeElement);
_prototype = new LinkedArea();
_prototype.setLink((LinkAttribute)((LinkAttribute) attrTypes.get("Link")).getAttributePrototype());
_prototype.getLink().setAttributeConfig(attributeElement);
}
@Override
public Element getJDOMElement() {
Element attributeElement = new Element("imagemap");
attributeElement.setAttribute("name", this.getName());
attributeElement.setAttribute("attributetype", "ImageMap");
this.setTimeStamp();
Element timestampElement = new Element("timestamp");
timestampElement.setText(this.getTimestamp());
attributeElement.addContent(timestampElement);
if (_image != null) {
attributeElement.addContent(_image.getJDOMElement());
if (_areas.size() > 0) {
Element areas = new Element("areas");
Iterator iteratorAreas = _areas.iterator();
while (iteratorAreas.hasNext()) {
Element area = new Element("area");
LinkedArea linkedArea = (LinkedArea) iteratorAreas.next();
area.setAttribute("shape", linkedArea.getShape());
area.setAttribute("coords", linkedArea.getCoords());
area.addContent(linkedArea.getLink().getJDOMElement());
areas.addContent(area);
}
attributeElement.addContent(areas);
}
}
return attributeElement;
}
public LinkedArea getArea(int index){
return _areas.get(index);
}
public LinkedArea addArea() {
LinkedArea newArea = (LinkedArea) this._prototype.clone();
newArea.setShape("rect");
//TODO per ora solo rect come forma
newArea.setCoords("0,0,0,0");
newArea.getLink().setDefaultLangCode(this.getDefaultLangCode());
this._areas.add(newArea);
return newArea;
}
public void removeArea(int index){
this._areas.remove(index);
}
public ImageAttribute getImage() {
if (null != _image) {
this._image.setDefaultLangCode(this.getDefaultLangCode());
this._image.setParentEntity(this.getParentEntity());
}
return _image;
}
public void setImage(ImageAttribute image) {
this._image = image;
}
private LinkedArea getPrototype() {
return this._prototype;
}
private void setPrototype(LinkedArea prototype) {
this._prototype = prototype;
}
@Override
public ResourceInterface getResource() {
if (this.getImage() != null) {
return this.getImage().getResource();
}
return null;
}
@Override
public ResourceInterface getResource(String langCode) {
return this.getResource();
}
@Override
public void setResource(ResourceInterface res, String langCode) {
if (this.getImage() != null) {
this.getImage().setResource(res, this.getDefaultLangCode());
}
}
public List<LinkedArea> getAreas() {
return this._areas;
}
public void setAreas(List<LinkedArea> areas) {
this._areas = areas;
}
public String getTimestamp() {
return _timestamp;
}
private void setTimeStamp() {
GregorianCalendar gregorianCalendar = new GregorianCalendar();
String timemillis = String.valueOf(gregorianCalendar.getTimeInMillis());
this.setTimeStamp(timemillis);
}
public void setTimeStamp(String timestamp) {
this._timestamp = timestamp;
}
@Override
public Object getValue() {
return this;
}
@Override
protected Object getJAXBValue(String langCode) {
JAXBImageMapValue imageMapValue = new JAXBImageMapValue();
JAXBResourceValue jaxbImageValue = (JAXBResourceValue) this.getImage().getJAXBAttribute(langCode).getValue();
imageMapValue.setImage(jaxbImageValue);
for (int i = 0; i < this.getAreas().size(); i++) {
LinkedArea area = this.getAreas().get(i);
JAXBAreaValue areaValue = new JAXBAreaValue();
JAXBLinkValue areaLinkValue = (JAXBLinkValue) area.getLink().getJAXBAttribute(langCode).getValue();
areaValue.setLink(areaLinkValue);
areaValue.setShape(area.getShape());
areaValue.setCoords(area.getCoords());
imageMapValue.addArea(areaValue);
}
return imageMapValue;
}
public void valueFrom(DefaultJAXBAttribute jaxbAttribute) {
JAXBImageMapValue value = (JAXBImageMapValue) jaxbAttribute.getValue();
if (null == value) return;
JAXBResourceValue jaxbImageValue = value.getImage();
if (null == jaxbImageValue) return;
try {
IResourceManager resourceManager = this.getResourceManager();
ResourceInterface resource = resourceManager.loadResource(jaxbImageValue.getResourceId().toString());
if (null != resource) {
this.setResource(resource, this.getDefaultLangCode());
}
if (null != value.getAreas()) {
for (int i = 0; i < value.getAreas().size(); i++) {
JAXBAreaValue areaValue = value.getAreas().get(i);
JAXBLinkValue areaLinkValue = areaValue.getLink();
if (null == areaValue || null == areaLinkValue) continue;
LinkedArea linkedArea = (LinkedArea) this.getPrototype().clone();
linkedArea.setShape(areaValue.getShape());
linkedArea.setCoords(areaValue.getCoords());
linkedArea.getLink().setSymbolicLink(areaLinkValue.getSymbolikLink());
Object textValue = areaLinkValue.getText();
if (null == textValue) return;
linkedArea.getLink().getTextMap().put(this.getDefaultLangCode(), textValue.toString());
}
}
} catch (Exception e) {
ApsSystemUtils.logThrowable(e, this, "valueFrom", "Error extracting linked area from jaxbAttribute");
}
}
protected IResourceManager getResourceManager() {
return (IResourceManager) this.getBeanFactory().getBean(JacmsSystemConstants.RESOURCE_MANAGER);
}
public Status getStatus() {
Status resourceStatus = (null != this.getResource()) ? Status.VALUED : Status.EMPTY;
Status linksStatus = (null != this.getAreas() && this.getAreas().size() > 0) ? Status.VALUED : Status.EMPTY;
if (!linksStatus.equals(resourceStatus)) return Status.INCOMPLETE;
if (linksStatus.equals(resourceStatus) && linksStatus.equals(Status.VALUED)) return Status.VALUED;
return Status.EMPTY;
}
public List<AttributeFieldError> validate(AttributeTracer tracer) {
List<AttributeFieldError> errors = super.validate(tracer);
try {
if (null == this.getResource()) return errors;
List<LinkedArea> areas = this.getAreas();
for (int i = 0; i < areas.size(); i++) {
LinkedArea area = (LinkedArea) areas.get(i);
AttributeTracer areaTracer = (AttributeTracer) tracer.clone();
areaTracer.setMonoListElement(true);
areaTracer.setListIndex(i);
LinkAttribute linkAttribute = area.getLink();
if (null != linkAttribute) {
errors.addAll(linkAttribute.validate(areaTracer));
}
String coords = area.getCoords();
boolean isShapeValued = (area.getShape() != null && area.getShape().trim().length() > 0 );
boolean isCoordsValued = (coords!= null && coords.trim().length() > 0 && this.isValidNumber(coords));
if (!isShapeValued || !isCoordsValued) {
errors.add(new AttributeFieldError(this, INVALID_LINKED_AREA_ERROR, areaTracer));
/*
String formFieldName = tracer.getFormFieldName(imageMapAttribute);
String[] args = { imageMapAttribute.getName(), String.valueOf(tracer.getListIndex()+1) };
this.addFieldError(action, formFieldName, "Content.linkedAreaElement.invalidArea.maskmsg", args);
*/
}
this.isIntersected(area, areaTracer, errors);
}
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "validate");
throw new RuntimeException("Error validating image map attribute", t);
}
return errors;
}
private boolean isValidNumber(String coords) {
Pattern pattern = Pattern.compile("^\\d+,\\d+,\\d+,\\d+$");
Matcher matcher = pattern.matcher(coords.trim());
return matcher.matches();
}
private void isIntersected(LinkedArea area, AttributeTracer tracer, List<AttributeFieldError> errors) {
int index = tracer.getListIndex();
Integer[] coordsArray = area.getArrayCoords();
if (null == coordsArray) return;
Rectangle areaRect =
new Rectangle(coordsArray[0].intValue(), coordsArray[1].intValue(), coordsArray[2].intValue() - coordsArray[0].intValue() , coordsArray[3].intValue() - coordsArray[1].intValue());
for (int i=index-1; i>=0 ; i--){
LinkedArea currentArea = this.getArea(i);
Integer[] currentCoordsArray = currentArea.getArrayCoords();
Rectangle currentAreaRect = new Rectangle(currentCoordsArray[0].intValue(),currentCoordsArray[1].intValue(),
currentCoordsArray[2].intValue() - currentCoordsArray[0].intValue() , currentCoordsArray[3].intValue() - currentCoordsArray[1].intValue());
boolean intersect = areaRect.intersects(currentAreaRect);
if (intersect) {
errors.add(new AttributeFieldError(this, INVALID_LINKED_AREA_ERROR, tracer));
}
}
}
public static final String INVALID_LINKED_AREA_ERROR = "INVALID_LINKED_AREA_ERROR";
public static final String INTERSECTED_AREA_ERROR = "INTERSECTED_AREA_ERROR";
private ImageAttribute _image;
private String _timestamp;
private List<LinkedArea> _areas = new ArrayList<LinkedArea>();
private LinkedArea _prototype;
}