/*
* Copyright 2011 Uwe Krueger.
*
* 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 com.mandelsoft.mand;
import com.mandelsoft.io.AbstractFile;
import com.mandelsoft.io.FileAbstractFile;
import com.mandelsoft.util.Utils;
import java.io.File;
import java.io.PrintStream;
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;
/**
*
* @author Uwe Krueger
*/
public class MandelImageDBContext {
private static class LabelMapping {
String src;
String dst;
String src_pattern;
String dst_pattern;
int len_src;
int len_dst;
public LabelMapping(String src, String dst)
{
this.src=src;
this.dst=dst;
this.src_pattern="@"+src+"~";
this.dst_pattern=":"+dst+"~";
this.len_src=src_pattern.length();
this.len_dst=dst_pattern.length();
}
}
public class ContextMapping implements ElementNameMapper {
private boolean complete;
private MandelImageDBContext context;
private String label;
private boolean direct;
private List<LabelMapping> mapping_in;
private List<LabelMapping> mapping_out;
ContextMapping(String label, MandelImageDBContext context, boolean direct)
{
this.context=context;
this.label = label;
this.direct = direct;
mapping_in = new ArrayList<LabelMapping>();
mapping_out = new ArrayList<LabelMapping>();
}
public String getLabel()
{
return label;
}
public MandelImageDBContext getContext()
{
return context;
}
public boolean isDirect()
{
return direct;
}
void complete() throws IllegalConfigurationException
{
if (complete) return;
context.complete();
for (ContextMapping m:context.mappings()) {
String l=MandelImageDBContext.this.getLabel(m.getContext());
if (l==null) {
addContext(m.getContext(),m.getLabel(),false);
}
else {
if (!l.equals(m.getLabel())) {
System.out.println("label mapping "+l+"->"+m.getLabel()+" for "+getContext().getRoot());
mapping_in.add(new LabelMapping(l, m.getLabel()));
mapping_out.add(new LabelMapping(m.getLabel(), l));
// throw new IllegalConfigurationException("inconsistent labels for "
// +m.getContext().getRoot());
}
}
}
complete=true;
}
//////////////////////////////////////////////////////////////////////
private StringBuilder sb=new StringBuilder();
private String mapLabelIn(String label)
{
if (label==null) {
throw new IllegalArgumentException("not in sub context");
}
if (!mapping_in.isEmpty()) for (LabelMapping m:mapping_in) {
if (m.src.equals(label)) {
return m.dst;
}
}
if (context.getContextMapping(label)!=null)
return label;
if (label.equals(this.label)) return null;
throw new IllegalArgumentException("unknown label in sub context");
}
private String mapLabelOut(String label)
{
if (label==null) return this.label;
if (!mapping_out.isEmpty()) for (LabelMapping m:mapping_out) {
if (m.src.equals(label)) {
return m.dst;
}
}
if (context.getContextMapping(label)!=null)
return label;
throw new IllegalArgumentException("unknown label in sub context");
}
private MandelName map(MandelName n, List<LabelMapping> mapping, boolean in)
{
String oe=n.getEffective();
String ol=n.getLabel();
String ne=oe;
String nl;
boolean changed=false;
if (n.isRoot()) return n;
if (ol==null) {
nl=label;
changed=true;
}
else {
if (in && ol.equals(label)) {
nl=null;
changed=true;
}
else {
nl=ol;
}
}
if (!mapping_out.isEmpty()) {
int ix;
boolean subst=false;
sb.setLength(0);
sb.append(n.getEffective());
for (LabelMapping m:mapping) {
while ((ix=sb.indexOf(m.src_pattern))>=0) {
sb.replace(ix, ix+m.len_src, m.dst_pattern);
subst=true;
}
if (ol!=null && ol.equals(m.src)) {
nl=m.dst;
changed=true;
}
}
if (subst) {
while ((ix=sb.indexOf(":"))>=0) {
sb.setCharAt(ix, ElementName.LABEL_START);
}
ne=sb.toString();
changed=true;
}
}
if (changed) {
n=new MandelName(ne, nl);
}
return n;
}
public QualifiedMandelName mapOut(QualifiedMandelName n)
{
MandelName mn=mapOut(n.getMandelName());
boolean maplabel=!n.isRoot()||(n.getQualifier()!=null);
return new QualifiedMandelName(mn,n.getQualifier(),
maplabel?mapLabelOut(n.getLabel()):null);
}
public QualifiedMandelName mapIn(QualifiedMandelName n)
{
MandelName mn=mapIn(n.getMandelName());
boolean maplabel=!n.isRoot()||(n.getQualifier()!=null);
return new QualifiedMandelName(mn,n.getQualifier(),
maplabel?mapLabelIn(n.getLabel()):null);
}
public MandelName mapOut(MandelName n)
{
return map(n,mapping_out,false);
}
public MandelName mapIn(MandelName n)
{
if (n.isRoot()) return n;
if ( n.isLocalName()) {
throw new IllegalArgumentException("no local name possible");
}
if (!label.equals(n.getLabel()) && mapLabelIn(n.getLabel())==null) {
throw new IllegalArgumentException("unknown label in sub context");
}
return map(n,mapping_in,true);
}
////////////////////////////////////////////////////////////////////////
public ColormapName mapOut(ColormapName n)
{
String nlabel=mapLabelOut(n.getLabel());
if (Utils.equals(n.getLabel(), nlabel)) return n;
return new ColormapName(n,nlabel);
}
public ColormapName mapIn(ColormapName n)
{
if (n.isLocalName()) {
throw new IllegalArgumentException("no local name possible");
}
String nlabel=mapLabelIn(n.getLabel());
if (!label.equals(n.getLabel()) && nlabel==null) {
throw new IllegalArgumentException("unknown label in sub context");
}
if (Utils.equals(n.getLabel(), nlabel)) return n;
return new ColormapName(n,nlabel);
}
}
//////////////////////////////////////////////////////////////////////
// context
//////////////////////////////////////////////////////////////////////
private boolean complete;
private MandelImageDB database;
private Map<String,ContextMapping> remote;
private Map<MandelImageDBContext,String> labels;
private Set<MandelImageDBContext> containers;
private AbstractFile root;
/*
* for testing
*/
public MandelImageDBContext(File root)
{
this(new FileAbstractFile(root),null);
}
public MandelImageDBContext(AbstractFile root, MandelImageDB db)
{
this.root=root;
this.database=db;
remote=new HashMap<String,ContextMapping>();
labels=new HashMap<MandelImageDBContext,String>();
containers=new HashSet<MandelImageDBContext>();
}
public MandelImageDB getDatabase()
{
return database;
}
void complete() throws IllegalConfigurationException
{
if (complete) return;
complete=true;
for (ContextMapping m: remote.values()) {
m.complete();
}
}
public boolean isComplete()
{
return complete;
}
public boolean hasNested()
{
return !remote.isEmpty();
}
public void addContext(MandelImageDBContext ctx, String label)
{
addContext(ctx,label,true);
}
void addContext(MandelImageDBContext ctx, String label, boolean direct)
{
if (ctx==this) return;
if (complete) {
throw new IllegalStateException("context for "+root+" already completed");
}
ContextMapping m=new ContextMapping(label,ctx,direct);
labels.put(ctx, label);
remote.put(label, m);
ctx.addContainer(this);
}
void addContainer(MandelImageDBContext ctx)
{
containers.add(ctx);
}
public AbstractFile getRoot()
{
return root;
}
public MandelImageDBContext getContext(String label)
{
ContextMapping m=getContextMapping(label);
return m==null?null:m.getContext();
}
public ContextMapping getContextMapping(String label)
{
return remote.get(label);
}
public String getLabel(MandelImageDBContext ctx)
{
return labels.get(ctx);
}
public ContextMapping getContextMapping(MandelImageDBContext ctx)
{
String label=getLabel(ctx);
if (label!=null) {
return getContextMapping(label);
}
return null;
}
//////////////////////////////////////////////////////////////////////////
public MandelName getMandelName(AbsoluteMandelName name)
{
return null;
}
//////////////////////////////////////////////////////////////////////////
private Iterable<ContextMapping> imappings=new Iterable<ContextMapping>() {
public Iterator<ContextMapping> iterator()
{
return remote.values().iterator();
}
};
public Iterable<ContextMapping> mappings()
{
return imappings;
}
private Iterable<MandelImageDBContext> icontainers=new Iterable<MandelImageDBContext>() {
public Iterator<MandelImageDBContext> iterator()
{
return containers.iterator();
}
};
public Iterable<MandelImageDBContext> containers()
{
return icontainers;
}
////////////////////////////////////////////////////////////////////////
public void print(PrintStream out, String gap)
{
String ngap=gap+" ";
out.println(gap+root);
if (!containers.isEmpty()) {
out.println(ngap+"containing databases:");
for (MandelImageDBContext ctx:containers) {
out.println(ngap+"- "+ctx.getRoot());
}
}
if (!remote.isEmpty()) {
out.println(ngap+"nested databases:");
for (String label:remote.keySet()) {
ContextMapping sub=remote.get(label);
out.println(ngap+"- "+label+" ("+(sub.isDirect()?"direct":"indirect")+")");
sub.getContext().print(out, ngap+" ");
}
}
}
////////////////////////////////////////////////////////////////////////
@Override
public boolean equals(Object obj)
{
if (obj==null) return false;
if (getClass()!=obj.getClass()) return false;
final MandelImageDBContext other=(MandelImageDBContext)obj;
if (this.root!=other.root&&(this.root==null||!this.root.equals(other.root)))
return false;
return true;
}
@Override
public int hashCode()
{
int hash=5;
hash=19*hash+(this.root!=null?this.root.hashCode():0);
return hash;
}
///////////////////////////////////////////////////////////////////////////
static int failed=0;
static boolean checkM(ContextMapping m, boolean in, String arg, String exp)
{
try {
QualifiedMandelName res;
QualifiedMandelName n=QualifiedMandelName._create(arg);
if (in) res=m.mapIn(n);
else res=m.mapOut(n);
if (res.toString().equals(exp)) {
System.out.println((in?"in":"out")+": "+arg+" -> "+res+" (OK)");
return true;
}
else {
System.out.println(
(in?"in":"out")+": "+arg+" -> "+res+" (FAILED) expected "+exp);
failed++;
return false;
}
}
catch (IllegalArgumentException ex) {
if (exp!=null) {
failed++;
System.out.println((in?"in":"out")+": "+arg+" -> <illegal> (FAILED) expected "
+exp+" ("+ex.getMessage()+")");
}
else {
System.out.println((in?"in":"out")+": "+arg+" -> <illegal> (OK)"
+" ("+ex.getMessage()+")");
}
return exp==null;
}
}
static boolean checkC(ContextMapping m, boolean in, String arg, String exp)
{
try {
ColormapName res;
ColormapName n=new ColormapName(arg);
if (in) res=m.mapIn(n);
else res=m.mapOut(n);
if (res.toString().equals(exp)) {
System.out.println((in?"in":"out")+": "+arg+" -> "+res+" (OK)");
return true;
}
else {
System.out.println(
(in?"in":"out")+": "+arg+" -> "+res+" (FAILED) expected "+exp);
failed++;
return false;
}
}
catch (IllegalArgumentException ex) {
if (exp!=null) {
failed++;
System.out.println((in?"in":"out")+": "+arg+" -> <illegal> (FAILED) expected "
+exp+" ("+ex.getMessage()+")");
}
else {
System.out.println((in?"in":"out")+": "+arg+" -> <illegal> (OK)"
+" ("+ex.getMessage()+")");
}
return exp==null;
}
}
public static void main(String[] args)
{
test();
}
public static int test()
{
System.out.println("starting MandelImageDBContext test...");
failed=0;
MandelImageDBContext root=new MandelImageDBContext(new File("root)"));
MandelImageDBContext lvl1=new MandelImageDBContext(new File("lvl1)"));
MandelImageDBContext lvl2=new MandelImageDBContext(new File("lvl2)"));
MandelImageDBContext lvl2a=new MandelImageDBContext(new File("lvl2)"));
lvl1.addContext(root, "root");
ContextMapping m1=lvl1.getContextMapping(root);
lvl2.addContext(root, "ROOT");
lvl2.addContext(lvl1, "lvl1");
ContextMapping m2=lvl2.getContextMapping(lvl1);
try {
lvl2.complete();
}
catch (IllegalConfigurationException ex) {
System.out.println("illegal config "+ex);
System.exit(1);
}
lvl2a.addContext(lvl1, "lvl1");
ContextMapping m2a=lvl2a.getContextMapping(lvl1);
//checkM(m1,false,"0","0@root");
checkM(m1, false, "0", "0");
checkM(m1, false, "abc", "abc@root");
checkM(m1, false, "0-qual", "0-qual@root");
checkM(m1, false, "abc-qual", "abc-qual@root");
checkM(m1, true, "abc", null);
//checkM(m1,true,"0@root","0");
checkM(m1, true, "0", "0");
checkM(m1, true, "abc@root", "abc");
checkM(m1, true, "abc-qual", null);
checkM(m1, true, "abc@root-qual", null);
checkM(m1, true, "0-qual@root", "0-qual");
//checkM(m1,true,"0@root-qual@root","0-qual");
checkM(m1, true, "0-qual@root", "0-qual");
checkM(m1, true, "abc-qual@root", "abc-qual");
//checkM(m2,false,"0@root","0@ROOT");
//checkM(m2,false,"0@root~a","0@ROOT~a@lvl1");
checkM(m2, false, "0", "0");
checkM(m2, false, "a", "a@lvl1");
checkM(m2, false, "a@root", "a@ROOT");
checkM(m2, false, "a@root~a", "a@ROOT~a@lvl1");
// checkM(m2,true,"0@ROOT","0@root");
// checkM(m2,true,"0@ROOT~a@lvl1","0@root~a");
// checkM(m2,true,"0@ROOT~a@lvl1~a",null);
// checkM(m2,true,"0@other",null);
checkM(m2, true, "0", "0");
checkM(m2, true, "a@lvl1", "a");
checkM(m2, true, "a@ROOT", "a@root");
checkM(m2, true, "a@ROOT~a@lvl1", "a@root~a");
checkM(m2, true, "a@ROOT~a@lvl1~a", null);
checkM(m2, true, "a@other", null);
// checkM(m2,true,"0@ROOT-qual",null);
// checkM(m2,true,"0@ROOT-qual@lvl1","0@root-qual");
checkM(m2, true, "a@ROOT-qual", null);
checkM(m2, true, "a@ROOT-qual@lvl1", "a@root-qual");
checkM(m2, true, "a-qual@lvl1", "a-qual");
checkM(m2, true, "a-qual@ROOT", "a-qual@root");
//////////////////////////////////////////////////////////////////////
checkC(m1, false, "cm1", "cm1@root");
checkC(m1, true, "cm1@root", "cm1");
//////////////////////////////////////////////////////////////////////
checkM(m2a,false, "a@root~a","a@root~a@lvl1");
checkM(m2a,true, "a@root~a@lvl1","a@root~a");
checkM(m2a,true, "a@root","a@root");
//////////////////////////////////////////////////////////////////////
System.out.println("failed: "+failed);
return failed;
}
}