package net.sf.eclipsefp.haskell.ui.internal.editors.cabal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sf.eclipsefp.haskell.core.cabalmodel.PackageDescription;
import net.sf.eclipsefp.haskell.core.cabalmodel.PackageDescriptionStanza;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
class CabalFoldingStructureProvider {
private final CabalFormEditor editor;
private IDocument document;
CabalFoldingStructureProvider( final CabalFormEditor editor ) {
this.editor = editor;
}
void setDocument( final IDocument document ) {
this.document = document;
}
void updateFoldingRegions( final PackageDescription pd ) {
if (editor==null){
return;
}
try {
Class<ProjectionAnnotationModel> ad = ProjectionAnnotationModel.class;
ProjectionAnnotationModel model
= ( ProjectionAnnotationModel )editor.getAdapter( ad );
if( model != null ) {
Set<Position> currentRegions = new HashSet<>();
addFoldingRegions( currentRegions, pd.getStanzas() );
updateFoldingRegions( model, currentRegions );
}
} catch( final BadLocationException badlox ) {
// ignore
}
}
private void updateFoldingRegions( final ProjectionAnnotationModel model,
final Set<Position> currentRegions ) {
Annotation[] deletions = diff( model, currentRegions );
Map<ProjectionAnnotation, Position> adds
= new HashMap<>();
Iterator<Position> it = currentRegions.iterator();
while( it.hasNext() ) {
adds.put( new ProjectionAnnotation(), it.next() );
}
if( ( deletions.length != 0 || adds.size() != 0 ) ) {
model.modifyAnnotations( deletions, adds, new Annotation[ 0 ] );
}
}
private Annotation[] diff( final ProjectionAnnotationModel model,
final Set<Position> current) {
List<ProjectionAnnotation> deletions= new ArrayList<>();
Iterator<?> it = model.getAnnotationIterator();
while( it.hasNext() ) {
Object annotation = it.next();
if( annotation instanceof ProjectionAnnotation ) {
Position position = model.getPosition( ( Annotation )annotation );
if( current.contains( position ) ) {
current.remove( position );
} else {
deletions.add( ( ProjectionAnnotation )annotation );
}
}
}
return deletions.toArray( new ProjectionAnnotation[ deletions.size() ] );
}
private void addFoldingRegions( final Set<Position> regions,
final Iterable<PackageDescriptionStanza> elements )
throws BadLocationException {
for( PackageDescriptionStanza element:elements) {
int startLine = element.getStartLine();
int endLine = element.getEndLine();
if( startLine < endLine ) {
int start = document.getLineOffset( startLine );
int end = document.getLength();
try {
end = document.getLineOffset( endLine-1 )
+ document.getLineLength( endLine-1 );
} catch( final BadLocationException badlox ) {
// ignore
}
Position position= new Position( start, end - start );
regions.add( position );
addFoldingRegions( regions, element.getStanzas() );
}
}
}
}