/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.foundation.dm.javaparser;
import java.util.logging.Logger;
import org.openflexo.diff.ComputeDiff;
import org.openflexo.diff.ComputeDiff.DiffReport;
import org.openflexo.foundation.TemporaryFlexoModelObject;
import org.openflexo.foundation.dm.DuplicateMethodSignatureException;
import org.openflexo.foundation.dm.dm.DMAttributeDataModification;
import org.openflexo.toolbox.StringUtils;
public abstract class AbstractSourceCode extends TemporaryFlexoModelObject {
@SuppressWarnings("unused")
private static final Logger logger = Logger.getLogger(AbstractSourceCode.class.getPackage().getName());
private SourceCodeOwner _owner;
private String _computedCode = null;
protected String _editedCode = null;
private boolean _hasParseError = false;
private String _parseErrorWarning = null;
private String _propertyName;
private String _hasParseErrorPropertyName;
private String _parseErrorWarningPropertyName;
protected AbstractSourceCode(SourceCodeOwner owner, String propertyName, String hasParseErrorPropertyName,
String parseErrorWarningPropertyName) {
this(owner);
_propertyName = propertyName;
_hasParseErrorPropertyName = hasParseErrorPropertyName;
_parseErrorWarningPropertyName = parseErrorWarningPropertyName;
}
protected AbstractSourceCode(SourceCodeOwner owner) {
super();
_owner = owner;
}
private static String getCleanCode(String code) {
if (code == null) {
return null;
}
String[] s = code.split("\n");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length; i++) {
String string = s[i];
if (string.length() > 0 && string.charAt(string.length() - 1) == '\r') {
sb.append(string.substring(0, string.length() - 1));
} else {
sb.append(string);
}
sb.append(StringUtils.LINE_SEPARATOR);
}
return sb.toString();
}
protected abstract boolean isJavaParserInstalled();
public boolean isEdited() {
return _editedCode != null;
}
public boolean hasParseErrors() {
return _hasParseError;
}
public void setHasParseErrors(boolean value) {
if (_hasParseError != value) {
_hasParseError = value;
if (_hasParseErrorPropertyName != null) {
getOwner().setChanged();
getOwner().notifyObservers(new DMAttributeDataModification(_hasParseErrorPropertyName, !_hasParseError, _hasParseError));
}
}
}
public String getParseErrorWarning() {
return _parseErrorWarning;
}
public void setParseErrorWarning(String warning) {
if (warning == null && _parseErrorWarning != null || warning != null && !warning.equals(_parseErrorWarning)) {
String oldValue = _parseErrorWarning;
_parseErrorWarning = warning;
if (_parseErrorWarningPropertyName != null) {
getOwner().setChanged();
getOwner().notifyObservers(new DMAttributeDataModification(_parseErrorWarningPropertyName, oldValue, warning));
}
}
}
public String updateComputedCode() {
_computedCode = getOwner().codeIsComputable() ? makeComputedCode() : null;
return _computedCode;
}
public String updateComputedCode(String someCode) {
someCode = getCleanCode(someCode);
_computedCode = someCode;
return _computedCode;
}
public abstract String makeComputedCode();
public abstract void interpretEditedCode(ParsedJavaElement javaElement) throws DuplicateMethodSignatureException;
private DiffReport diffReport;
private boolean diffReportNeedsToBeRecomputed = true;
public DiffReport getDiffReport() {
if (diffReportNeedsToBeRecomputed) {
diffReport = null;
updateComputedCode();
if (getCode() != null && _computedCode != null) {
diffReport = ComputeDiff.diff(getCode(), _computedCode);
}
}
return diffReport;
}
/**
* Return code this method represents
*
* @return
*/
public String getCode() {
// No need to serialize if not edited
if (getOwner().isSerializing() && !isEdited()) {
return null;
}
if (isEdited()) {
return _editedCode;
}
if (_computedCode == null && !getOwner().isDeserializing()) {
updateComputedCode();
}
return _computedCode;
}
/*public String getIndentedCode()
{
String codeToIndent = getCode();
BufferedReader rdr = new BufferedReader(new StringReader(codeToIndent));
StringBuffer sb = new StringBuffer();
boolean firstLine = true;
for (;;) {
String line = null;
try {
line = rdr.readLine();
} catch (IOException e) {
e.printStackTrace();
}
if (line == null) break;
sb.append(firstLine?line+LINE_SEPARATOR:"\t"+line+LINE_SEPARATOR);
firstLine = false;
}
return sb.toString();
}*/
/**
* Sets code this method represents, and when not deserializing, update owner object with informations contained in supplied qualified
* code.
*
* @param qualifiedCode
* @throws ParserNotInstalledException
* @throws DuplicateMethodSignatureException
* @throws UnresolvedTypesException
*/
public void setCode(final String qualifiedCode) throws ParserNotInstalledException, DuplicateMethodSignatureException {
if (getOwner() != null && getOwner().isDeserializing()) {
if (isJavaParserInstalled()) {
parseCode(qualifiedCode);
}
setCode(qualifiedCode, false);
} else {
setCode(qualifiedCode, true);
}
}
/**
* Sets code this method represents, and if parseCode flag is set to true, update owner object with informations contained in supplied
* qualified code.
*
* @param someCode
* @param parseCode
* @throws ParserNotInstalledException
* @throws DuplicateMethodSignatureException
* @throws UnresolvedTypesException
*/
public void setCode(String someCode, boolean parseCode) throws ParserNotInstalledException, DuplicateMethodSignatureException {
diffReportNeedsToBeRecomputed = true;
someCode = getCleanCode(someCode);
if (_computedCode == null && getOwner().codeIsComputable()) {
_computedCode = makeComputedCode();
}
if (someCode == null || someCode.trim().equals("") || someCode.trim().equals(_computedCode)) {
// Use computed code
_editedCode = null;
updateComputedCode();
if (_propertyName != null) {
getOwner().setChanged();
getOwner().notifyObserversAsReentrantModification(new DMAttributeDataModification(_propertyName, null, someCode));
}
_parseErrorWarning = null;
setHasParseErrors(false);
return;
}
if (someCode.equals(getCode())) {
// Unchanged, just return;
return;
}
_editedCode = someCode;
if (!parseCode) {
return;
}
ParsedJavaElement parsedJavaElement = parseCode(someCode);
if (parsedJavaElement != null) {
// It's parsable, try to interpret this
interpretEditedCode(parsedJavaElement);
if (_propertyName != null) {
getOwner().setChanged();
getOwner().notifyObserversAsReentrantModification(new DMAttributeDataModification(_propertyName, null, someCode));
}
}
}
protected abstract ParsedJavaElement parseCode(final String qualifiedCode) throws ParserNotInstalledException;
protected abstract ParsedJavadoc parseJavadoc(final String qualifiedCode) throws ParserNotInstalledException;
public SourceCodeOwner getOwner() {
return _owner;
}
public void setOwner(SourceCodeOwner owner) {
_owner = owner;
}
public void replaceJavadocInEditedCode(ParsedJavadoc newJavadoc) {
replaceJavadocInEditedCode(newJavadoc.getStringRepresentation());
}
public void replaceJavadocInEditedCode(String newJavadoc) {
// logger.info("Called replaceJavadocInEditedCode()");
// First look javadoc
int javadocBeginIndex = _editedCode.indexOf("/**");
if (javadocBeginIndex > -1) {
int endJavadocIndex = _editedCode.indexOf("*/") + 2 + StringUtils.LINE_SEPARATOR.length();
_editedCode = _editedCode.substring(0, javadocBeginIndex) + newJavadoc + _editedCode.substring(endJavadocIndex);
} else {
_editedCode = newJavadoc + _editedCode;
}
}
}