/*******************************************************************************
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package hr.fer.zemris.vhdllab.applets.editor.schema2.model.queries;
import hr.fer.zemris.vhdllab.applets.editor.schema2.enums.EPropertyChange;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IQuery;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IQueryResult;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaInfo;
import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaWire;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.Caseless;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.WireSegment;
import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.XYLocation;
import hr.fer.zemris.vhdllab.applets.editor.schema2.model.QueryResult;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Postavlja upit o tome koliko navedena zica ima odvojenih skupova
* segmenata. Ako je zica povezana segmentima u jednu cjelinu,
* vratit ce se lista s jednim skupom segmenata koji sadrzi sve segmente.
* Ako zica nema segmenata, vratit ce se prazna lista segmenata.
*
* Rezultat se vraca unutar QueryResult-a pod kljucem KEY_SEGMENT_SETS,
* ako je pretraga uspjesna.
* Vrijednost pohranjena pod tim kljucem je tipa DisjointSets (inner klasa
* ovog Query-a). DisjointSets sadrzi listu skupova segmenata.
*
* @author brijest
*
*/
public class FindDisjointSegments implements IQuery {
public static class DisjointSets {
public List<Set<WireSegment>> segmentsets = new ArrayList<Set<WireSegment>>();
}
private static class SegmentHolder {
public WireSegment seg;
public boolean ishandled = false;
public SegmentHolder(WireSegment ws) { seg = ws; }
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (!(obj instanceof SegmentHolder)) return false;
SegmentHolder holder = (SegmentHolder)obj;
return (this.seg.equals(holder.seg));
}
@Override
public int hashCode() {
return seg.hashCode();
}
}
/* static fields */
public static final String QUERY_NAME = FindDisjointSegments.class.getSimpleName();
public static final String KEY_SEGMENT_SETS = "segment_sets";
private static final List<EPropertyChange> propdepend = new ArrayList<EPropertyChange>();
private static final List<EPropertyChange> ro_pd = Collections.unmodifiableList(propdepend);
{
propdepend.add(EPropertyChange.CANVAS_CHANGE);
propdepend.add(EPropertyChange.PROPERTY_CHANGE);
}
/* private fields */
private Caseless wirename;
/* ctors */
public FindDisjointSegments(Caseless wireToAnalyze) {
wirename = wireToAnalyze;
}
/* methods */
public List<EPropertyChange> getPropertyDependency() {
return ro_pd;
}
public boolean isCacheable() {
return true;
}
public String getQueryName() {
return QUERY_NAME;
}
public IQueryResult performQuery(ISchemaInfo info) {
ISchemaWire wire = info.getWires().fetchWire(wirename);
if (wire == null) {
return new QueryResult(false);
}
if (wire.getSegments().size() == 0) {
return new QueryResult(KEY_SEGMENT_SETS, new DisjointSets());
}
dissets = new DisjointSets();
tohandlesegs = new HashSet<SegmentHolder>();
segmentmap = new HashMap<XYLocation, List<SegmentHolder>>();
// put all segments into a location based map and the tohandle list
for (WireSegment segment : wire.getSegments()) {
SegmentHolder seghold = new SegmentHolder(segment);
List<SegmentHolder> segs = segmentmap.get(segment.getStart());
if (segs == null) {
segs = new ArrayList<SegmentHolder>();
segmentmap.put(segment.getStart(), segs);
}
segs.add(seghold);
segs = segmentmap.get(segment.getEnd());
if (segs == null) {
segs = new ArrayList<SegmentHolder>();
segmentmap.put(segment.getEnd(), segs);
}
segs.add(seghold);
tohandlesegs.add(seghold);
}
// pick unhandled segments and handle them recursively
for (SegmentHolder holder : tohandlesegs) {
if (holder.ishandled == false) {
Set<WireSegment> wsset = new HashSet<WireSegment>();
dissets.segmentsets.add(wsset);
rec_handle_segment(holder, wsset);
}
}
segmentmap = null;
tohandlesegs = null;
return new QueryResult(KEY_SEGMENT_SETS, dissets);
}
private DisjointSets dissets;
private Map<XYLocation, List<SegmentHolder>> segmentmap;
private Set<SegmentHolder> tohandlesegs;
private void rec_handle_segment(SegmentHolder holder, Set<WireSegment> wsset) {
// handle this holder
holder.ishandled = true;
wsset.add(holder.seg);
// handle unhandled neighbours
List<SegmentHolder> segholds = segmentmap.get(holder.seg.getStart());
for (SegmentHolder sh : segholds) if (sh.ishandled == false) rec_handle_segment(sh, wsset);
segholds = segmentmap.get(holder.seg.getEnd());
for (SegmentHolder sh : segholds) if (sh.ishandled == false) rec_handle_segment(sh, wsset);
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (!(obj instanceof FindDisjointSegments)) return false;
FindDisjointSegments other = (FindDisjointSegments)obj;
return other.wirename.equals(this.wirename);
}
@Override
public int hashCode() {
return wirename.hashCode();
}
@Override
public String toString() {
return super.toString();
}
}