/**
* This file Copyright (c) 2005-2008 Aptana, Inc. This program is
* dual-licensed under both the Aptana Public License and the GNU General
* Public license. You may elect to use one or the other of these licenses.
*
* This program is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. Redistribution, except as permitted by whichever of
* the GPL or APL you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or modify this
* program under the terms of the GNU General Public License,
* Version 3, as published by the Free Software Foundation. You should
* have received a copy of the GNU General Public License, Version 3 along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Aptana provides a special exception to allow redistribution of this file
* with certain other free and open source software ("FOSS") code and certain additional terms
* pursuant to Section 7 of the GPL. You may view the exception and these
* terms on the web at http://www.aptana.com/legal/gpl/.
*
* 2. For the Aptana Public License (APL), this program and the
* accompanying materials are made available under the terms of the APL
* v1.0 which accompanies this distribution, and is available at
* http://www.aptana.com/legal/apl/.
*
* You may view the GPL, Aptana's exception and additional terms, and the
* APL in the file titled license.html at the root of the corresponding
* plugin containing this source file.
*
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.ide.editor.scriptdoc.parsing;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import com.aptana.ide.editor.js.environment.LexemeConsumerHelper;
import com.aptana.ide.editor.js.runtime.Reference;
import com.aptana.ide.editors.managers.EnvironmentManager;
import com.aptana.ide.editors.managers.FileContextManager;
import com.aptana.ide.lexer.Lexeme;
import com.aptana.ide.metadata.IDocumentation;
import com.aptana.ide.metadata.IDocumentationStore;
import com.aptana.ide.parsing.CodeLocation;
import com.aptana.ide.parsing.IParseState;
/**
* @author Robin Debreuil
*/
public class ScriptDocStore implements IDocumentationStore
{
private Map<Integer,IDocumentation> _scriptObjects;
private IParseState _parseState;
/**
* ScriptDocStore
* @param parseState
*/
public ScriptDocStore(IParseState parseState)
{
this._parseState = parseState;
this._scriptObjects = new HashMap<Integer,IDocumentation>();
}
/**
* @see com.aptana.ide.metadata.IDocumentationStore#clear()
*/
public void clear()
{
this._scriptObjects.clear();
//idMap.clear();
}
/**
* @see com.aptana.ide.metadata.IDocumentationStore#addScriptDocObject(int, com.aptana.ide.lexer.Lexeme, com.aptana.ide.metadata.IDocumentation)
*/
public void addScriptDocObject(int offset, Lexeme lx, IDocumentation doc)
{
String uri = FileContextManager.getURIFromFileIndex(this._parseState.getFileIndex());
// dups shouldn't happen as list is cleared each parse
if (this._scriptObjects.containsKey(offset))
{
this._scriptObjects.remove(offset);
}
// deal with @id mapped scripts
if (doc.getIDs().length > 0)
{
Map<String, IDocumentation> idMap = EnvironmentManager.getDocumentationIdMap();
String[] ids = doc.getIDs();
String id = ids[0]; // todo: use all ids
if (idMap.containsKey(id))
{
IDocumentation oldDoc = idMap.get(id);
mergeScriptDocs(id, oldDoc, doc);
this._scriptObjects.put(offset, oldDoc);
// add the location to the doc if it has an @id regardless, as we want to know all of these
if ("".equals(uri) == false && oldDoc instanceof DocumentationBase) //$NON-NLS-1$
{
CodeLocation[] codeLoc = doc.getID(id);
for (int i = 0; i < codeLoc.length; i++)
{
CodeLocation location = codeLoc[i];
oldDoc.setID(id, location);
}
//DocumentationBase db = (DocumentationBase) oldDoc;
//CodeLocation codeLoc = new CodeLocation(fullPath, lx);
//db.addIDLocation(codeLoc);
}
}
else
{
idMap.put(id, doc);
Map refMap = EnvironmentManager.getDocumentationRefMap();
this._scriptObjects.put(offset, doc);
Reference ref = LexemeConsumerHelper.addDocHolderToEnvironment(id, doc, this._parseState);
if (ref != null)
{
refMap.put(id, ref);
}
// add the location to the doc if it has an @id regardless, as we want to know all of these
// if(fullPath != "" && doc instanceof DocumentationBase)
// {
// DocumentationBase db = (DocumentationBase) doc;
// CodeLocation codeLoc = new CodeLocation(fullPath, null, lx);
// db.addIDLocation(codeLoc);
// }
}
}
else
{
this._scriptObjects.put(offset, doc);
}
}
/**
* @see com.aptana.ide.metadata.IDocumentationStore#getDocumentationFromOffset(int)
*/
public IDocumentation getDocumentationFromOffset(int offset)
{
return this._scriptObjects.get(offset);
}
/**
* Merges the second doc into the originalDoc (only if they have the same ID).
* AddedDoc always takes precidence in case of conflict.
* @param originalDoc
* @param addedDoc
*/
private void mergeScriptDocs(String id, IDocumentation originalDoc, IDocumentation addedDoc)
{
String[] ids = addedDoc.getIDs();
boolean hasMatch = false;
for (int i = 0; i < ids.length; i++)
{
if (id.equals(ids[i]))
{
hasMatch = true;
break;
}
}
if (!hasMatch)
{
return;
}
// default props
if (!addedDoc.getAuthor().equals("")) //$NON-NLS-1$
{
originalDoc.setAuthor(addedDoc.getAuthor());
}
if (!addedDoc.getDescription().equals("")) //$NON-NLS-1$
{
originalDoc.setDescription(addedDoc.getDescription());
}
//if(originalDoc.getDocumentType() == IDocumentation.TYPE_FUNCTION) // default
// originalDoc.setDocumentType(addedDoc.getDocumentType());
String[] examples = addedDoc.getExamples();
if (examples.length > 0) //$NON-NLS-1$
{
for (int i = 0; i < examples.length; i++)
{
originalDoc.addExample(examples[i]);
}
}
if (!addedDoc.getName().equals("")) //$NON-NLS-1$
{
originalDoc.setName(addedDoc.getName());
}
if (!addedDoc.getRemarks().equals("")) //$NON-NLS-1$
{
originalDoc.setRemarks(addedDoc.getRemarks());
}
if (!addedDoc.getUserAgent().equals("")) //$NON-NLS-1$
{
originalDoc.setUserAgent(addedDoc.getUserAgent());
}
if (!addedDoc.getVersion().equals("")) //$NON-NLS-1$
{
originalDoc.setVersion(addedDoc.getVersion());
}
if (originalDoc instanceof PropertyDocumentation && addedDoc instanceof PropertyDocumentation)
{
PropertyDocumentation doc = (PropertyDocumentation)originalDoc;
PropertyDocumentation doc2 = (PropertyDocumentation)addedDoc;
if (!doc2.getDeprecatedDescription().equals("")) //$NON-NLS-1$
{
doc.setDeprecatedDescription(doc2.getDeprecatedDescription());
}
//if(doc2.getIsDeprecatedSet())
doc.setIsDeprecated(doc2.getIsDeprecated());
//if(doc2.getIsIgnoredSet())
doc.setIsIgnored(doc2.getIsIgnored());
//if(doc2.getIsInstanceSet())
doc.setIsInstance(doc2.getIsInstance());
//if(doc2.getIsInternalSet())
doc.setIsInternal(doc2.getIsInternal());
//if(doc2.getIsInvocationOnlySet())
doc.setIsInvocationOnly(doc2.getIsInvocationOnly());
//if(doc2.getIsNativeSet())
doc.setIsNative(doc2.getIsNative());
//if(doc2.getIsPrivateSet())
doc.setIsPrivate(doc2.getIsPrivate());
//if(doc2.getIsProtectedSet())
doc.setIsProtected(doc2.getIsProtected());
if (!doc2.getSince().equals("")) //$NON-NLS-1$
{
doc.setSince(doc2.getSince());
}
mergeTypedDescriptions(doc.getAliases(), doc2.getAliases());
mergeTypedDescriptions(doc.getMemberOf(), doc2.getMemberOf());
mergeTypedDescriptions(doc.getReturn(), doc2.getReturn());
}
if (originalDoc instanceof FunctionDocumentation && addedDoc instanceof FunctionDocumentation)
{
FunctionDocumentation doc = (FunctionDocumentation)originalDoc;
FunctionDocumentation doc2 = (FunctionDocumentation)addedDoc;
if (!doc2.getDeprecatedDescription().equals("")) //$NON-NLS-1$
{
doc.setClassDescription(doc2.getDeprecatedDescription());
}
//if(doc2.getIsConstructorSet())
doc.setIsConstructor(doc2.getIsConstructor());
//if(doc2.getIsMethodSet())
doc.setIsMethod(doc2.getIsMethod());
if (doc2.getParams().length != 0)
{
// todo: may need to merge these based on names and actual function def
doc.clearParams();
TypedDescription[] params = doc2.getParams();
for (int i = 0; i < params.length; i++)
{
TypedDescription description = params[i];
doc.addParam(description);
}
}
if (doc2.getExceptions().length != 0)
{
TypedDescription[] exceptions = doc2.getExceptions();
doc.clearExceptions();
for (int i = 0; i < exceptions.length; i++)
{
TypedDescription description = exceptions[i];
doc.addParam(description);
}
}
mergeTypedDescriptions(doc.getExtends(), doc2.getExtends());
}
}
/**
* Merges the addedDesc into the dominatDesc parameter
* @param originalDesc
* @param addedDesc
*/
private void mergeTypedDescriptions(TypedDescription originalDesc, TypedDescription addedDesc)
{
if (!addedDesc.getName().equals("")) //$NON-NLS-1$
{
originalDesc.setName(addedDesc.getName());
}
if (!addedDesc.getDescription().equals("")) //$NON-NLS-1$
{
originalDesc.setDescription(addedDesc.getDescription());
}
if (addedDesc.getTypes().length != 0)
{
String[] types = addedDesc.getTypes();
originalDesc.clearTypes();
for (int i = 0; i < types.length; i++)
{
originalDesc.addType(types[i]);
}
}
if (originalDesc.getDefaultValues().length == 0)
{
TypedDescription[] vals = addedDesc.getDefaultValues();
originalDesc.clearDefaultValues();
for (int i = 0; i < vals.length; i++)
{
originalDesc.addDefaultValue(vals[i]);
}
}
}
/**
* @see com.aptana.ide.metadata.IDocumentationStore#getDocumentationObjects()
*/
public IDocumentation[] getDocumentationObjects()
{
return this._scriptObjects.values().toArray(new IDocumentation[0]);
}
/**
* @see com.aptana.ide.metadata.IDocumentationStore#getDocumentationOffsets()
*/
public int[] getDocumentationOffsets()
{
Set<Integer> docs = this._scriptObjects.keySet();
int[] array = new int[docs.size()];
int i = 0;
for (Iterator<Integer> iter = docs.iterator(); iter.hasNext(); ) {
Integer element = iter.next();
array[i] = element.intValue();
i++;
}
Arrays.sort(array);
return array;
}
}