/*
* 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 java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import com.mandelsoft.util.Utils;
/**
*
* @author Uwe Krueger
*/
public class MandelInfo extends MandelSpec
implements MandelData.Part {
static private final int VERSION=4;
private int version; // found version
private boolean hidden; // hidden area: hint for ui
// content relted image information
private int minit; // minimum iteration
private int maxit; // maximum iterations
private long numit; // number of total iteration steps
private int time; // calculation time in seconds
private int efftime; // effective calculation time
private long creattime; // creation time
private long calctime; // raster creation time
private long imgtime; // image creation time
// internal calculation related information
private int usedlimit; // limit used for last calculation
private long mccnt; // calculated number of mandel set pixels
private long mcnt; // number of mandel set pixel
private String name; // assigned name
private String location; // assigned location spec
private String creator; // creator
private String site; // creation site
private Set<String> keywords; // keywords for classification
public MandelInfo()
{ super();
setup();
}
public MandelInfo(double xm, double ym,
double dx, double dy,
int rx, int ry, int limitit, boolean hidden)
{
this(BigDecimal.valueOf(xm),BigDecimal.valueOf(ym),
BigDecimal.valueOf(dx),BigDecimal.valueOf(dy),
rx,ry,limitit,hidden);
}
public MandelInfo(BigDecimal xm, BigDecimal ym,
BigDecimal dx, BigDecimal dy,
int rx, int ry, int limitit, boolean hidden)
{ super(xm,ym,dx,dy,rx,ry,limitit);
setup();
this.hidden=hidden;
}
public MandelInfo(MandelInfo mi)
{
this(mi,mi);
}
public MandelInfo(MandelSpec spec, MandelInfo mi)
{
this(spec.getXM(), spec.getYM(),
spec.getDX(), spec.getDY(),
spec.getRX(), spec.getRY(),
spec.getLimitIt(),mi==null?false:mi.hidden);
if (mi!=null) {
setName(mi.getName());
setLocation(mi.getLocation());
setCreator(mi.getCreator());
setSite(mi.getSite());
setKeywords(mi.getKeywords());
}
}
private void setup()
{
this.version=VERSION;
this.name="";
this.location="";
this.creator=null;
this.site=null;
}
public MandelInfo copyFrom(MandelInfo o)
{
setInfo(o);
return this;
}
public int getVersion()
{
return version;
}
public boolean isHidden()
{
return hidden;
}
public int getMinIt()
{
return minit;
}
public int getMaxIt()
{
return maxit;
}
// content related data
public long getNumIt()
{
return numit;
}
public int getTime()
{
return time;
}
public int getEffectiveTime()
{
return efftime;
}
public long getCreationTime()
{
return creattime;
}
public long getRasterCreationTime()
{
return calctime;
}
public long getImageCreationTime()
{
return imgtime;
}
public String getLocation()
{
return location;
}
public String getName()
{
return name;
}
public String getCreator()
{
return creator;
}
public String getSite()
{
return site;
}
public Set<String> getKeywords()
{
if (keywords==null) keywords=new HashSet<String>();
return new HashSet(keywords);
}
public long getMCCnt()
{
return mccnt;
}
public long getMCnt()
{
return mcnt;
}
public int getUsedLimit()
{
return usedlimit;
}
public int getTargetSize()
{ return getMaxIt()-getMinIt()+2;
}
// setter
public void setInfo(MandelInfo i)
{ setInfo(i,true);
}
public void setInfo(MandelInfo i, boolean full)
{
setSpec(i);
setHidden(i.isHidden());
if (full) {
setMinIt(i.getMinIt());
setMaxIt(i.getMaxIt());
setNumIt(i.getNumIt());
setTime(i.getTime());
setEffectiveTime(i.getEffectiveTime());
setMCCnt(i.getMCCnt());
setMCnt(i.getMCnt());
setUsedLimit(i.getUsedLimit());
setCreationTime(i.getCreationTime());
setRasterCreationTime(i.getRasterCreationTime());
setImageCreationTime(i.getImageCreationTime());
}
setName(i.getName());
setLocation(i.getLocation());
setCreator(i.getCreator());
setSite(i.getSite());
setKeywords(i.getKeywords());
version=i.version;
}
public void setHidden(boolean hidden)
{
this.hidden=hidden;
}
// content related data
public void setMinIt(int minit)
{
this.minit=minit;
}
public void setMaxIt(int maxit)
{
this.maxit=maxit;
}
public void setNumIt(long numit)
{
this.numit=numit;
}
public void setTime(int time)
{
this.time=time;
}
public void setEffectiveTime(int efftime)
{
this.efftime=efftime;
}
public void setMCCnt(long mccnt)
{
this.mccnt=mccnt;
}
public void setMCnt(long mcnt)
{
this.mcnt=mcnt;
}
public void setUsedLimit(int usedlimit)
{
this.usedlimit=usedlimit;
}
public void setCreationTime(long t)
{
creattime=t;
}
public void setRasterCreationTime(long t)
{
calctime=t;
}
public void setImageCreationTime(long t)
{
imgtime=t;
}
public void setLocation(String location)
{
if (location==null) location="";
//System.out.println("location is "+location);
this.location=location;
}
public void setName(String name)
{
if (name==null) name="";
this.name=name;
}
public void setCreator(String creator)
{
this.creator=creator;
}
public void setSite(String site)
{
this.site=site;
}
public void setKeywords(Set<String> k)
{
if (keywords==null) keywords=new HashSet<String>(k);
else {
keywords.clear();
keywords.addAll(k);
}
}
public boolean hasMandelCount()
{
if (version>=2) return true;
return mcnt_set;
}
///////////////////////////////////////////////////////////////
// version update
///////////////////////////////////////////////////////////////
private boolean mcnt_set=false;
public void updateData(MandelData data)
{
if (version==1 && mcnt==0 && data.getRaster()!=null) {
MandelRaster raster=data.getRaster();
int[][] r=raster.getRaster();
int rx=raster.getRX();
int ry=raster.getRY();
for (int x=0; x<rx; x++) {
for (int y=0; y<ry; y++) {
if (r[y][x]==0) mcnt++;
}
}
mcnt_set=true;
}
}
///////////////////////////////////////////////////////////////
// io
///////////////////////////////////////////////////////////////
public boolean needsVersionUpdate()
{
//System.out.println("version is "+version);
return version!=VERSION;
}
public void write(DataOutputStream dos) throws IOException
{
write(dos,VERSION);
}
public void write(DataOutputStream dos, boolean verbose) throws IOException
{
write(dos,VERSION,verbose);
}
public void write(DataOutputStream dos, int v) throws IOException
{
write(dos,v,true);
}
public void write(DataOutputStream dos, int v, boolean verbose)
throws IOException
{
if (verbose) System.out.println(" writing info ("+v+") ...");
switch (v) {
case 1: dos.writeInt(v);
writeV1(dos);
break;
case 2: dos.writeInt(v);
writeV2(dos);
break;
case 3: dos.writeInt(v);
writeV3(dos);
break;
case 4: dos.writeInt(v);
writeV4(dos);
break;
default: throw new IOException("unknown mandel info version "+v);
}
}
private void writeV1(DataOutputStream dos) throws IOException
{
// fixed format
dos.writeDouble(getXM().doubleValue());
dos.writeDouble(getYM().doubleValue());
dos.writeDouble(getDX().doubleValue());
dos.writeDouble(getDY().doubleValue());
dos.writeInt(getRX());
dos.writeInt(getRY());
dos.writeInt(getLimitIt());
dos.writeInt(minit);
dos.writeInt(maxit);
dos.writeLong(numit);
dos.writeInt(time);
// extension
dos.writeUTF(name);
dos.writeUTF(location);
}
private void writeV2(DataOutputStream dos) throws IOException
{
dos.writeUTF(getXM().toString());
dos.writeUTF(getYM().toString());
dos.writeUTF(getDX().toString());
dos.writeUTF(getDY().toString());
dos.writeInt(getRX());
dos.writeInt(getRY());
dos.writeInt(getLimitIt());
dos.writeBoolean(hidden);
dos.writeInt(minit);
dos.writeInt(maxit);
dos.writeLong(numit);
dos.writeInt(time);
dos.writeInt(usedlimit);
dos.writeLong(mcnt);
dos.writeLong(mccnt);
// extension
dos.writeUTF(name);
dos.writeUTF(location);
}
private void writeV3(DataOutputStream dos) throws IOException
{
writeV2(dos);
dos.writeUTF(mapWrite(creator));
dos.writeUTF(mapWrite(site));
}
private void writeV4(DataOutputStream dos) throws IOException
{
writeV3(dos);
dos.writeInt(efftime);
dos.writeLong(creattime);
dos.writeLong(calctime);
dos.writeLong(imgtime);
StringBuffer sb=new StringBuffer();
if (keywords!=null) {
String sep="";
for (String s:keywords) {
sb.append(sep);
sb.append(s);
sep=",";
}
}
dos.writeUTF(sb.toString());
}
public void read(DataInputStream dis) throws IOException
{
read(dis,true);
}
public void read(DataInputStream dis, boolean verbose) throws IOException
{
if (verbose) System.out.println(" reading info ...");
version=dis.readInt();
switch (version) {
case 1: readV1(dis);
break;
case 2: readV2(dis);
break;
case 3: readV3(dis);
break;
case 4: readV4(dis);
break;
default: throw new IOException("unknown mandel info version "+version);
}
}
private void readV1(DataInputStream dis) throws IOException
{
// fixed format
setXM(BigDecimal.valueOf(dis.readDouble()));
setYM(BigDecimal.valueOf(dis.readDouble()));
setDX(BigDecimal.valueOf(dis.readDouble()));
setDY(BigDecimal.valueOf(dis.readDouble()));
setRX(dis.readInt());
setRY(dis.readInt());
setLimitIt(dis.readInt());
minit=dis.readInt();
maxit=dis.readInt();
numit=dis.readLong();
time=dis.readInt();
// extension
name=dis.readUTF();
location=dis.readUTF();
}
private void readV2(DataInputStream dis) throws IOException
{
// fixed format
setXM(new BigDecimal(dis.readUTF()));
setYM(new BigDecimal(dis.readUTF()));
setDX(new BigDecimal(dis.readUTF()));
setDY(new BigDecimal(dis.readUTF()));
setRX(dis.readInt());
setRY(dis.readInt());
setLimitIt(dis.readInt());
hidden=dis.readBoolean();
minit=dis.readInt();
maxit=dis.readInt();
numit=dis.readLong();
time=dis.readInt();
usedlimit=dis.readInt();
mcnt=dis.readLong();
mccnt=dis.readLong();
// extension
name=dis.readUTF();
location=dis.readUTF();
}
private void readV3(DataInputStream dis) throws IOException
{
readV2(dis);
creator=mapRead(dis.readUTF());
site=mapRead(dis.readUTF());
efftime=time;
}
private void readV4(DataInputStream dis) throws IOException
{
readV3(dis);
efftime=dis.readInt();
creattime=dis.readLong();
calctime=dis.readLong();
imgtime=dis.readLong();
if (keywords==null) keywords=new HashSet<String>();
else keywords.clear();
StringTokenizer t=new StringTokenizer(dis.readUTF(),",");
while (t.hasMoreTokens()) {
keywords.add(t.nextToken());
}
}
private String mapRead(String s)
{ return Utils.isEmpty(s)?null:s;
}
private String mapWrite(String s)
{ return s==null?"":s;
}
/////////////////////////////////////////////////////////////////////////
private boolean _false(String reason)
{
System.out.println("mismatch: "+reason);
return false;
}
@Override
public boolean equals(Object obj)
{
if (obj==null) return false;
if (getClass()!=obj.getClass()) return _false("class");
final MandelInfo other=(MandelInfo)obj;
if (!super.equals(obj)) return _false("spec");
if (this.version!=other.version) return _false("version");
if (this.minit!=other.minit) return _false("minit");
if (this.maxit!=other.maxit) return _false("maxit");
if (this.numit!=other.numit) return _false("numit");
if (this.time!=other.time) return _false("time");
if (this.efftime!=other.efftime) return _false("efftime");
if (this.creattime!=other.creattime) return _false("creattime");
if (this.calctime!=other.calctime) return _false("calctime");
if (this.imgtime!=other.imgtime) return _false("imgtime");
if (this.usedlimit!=other.usedlimit) return _false("usedlimit");
if (this.mccnt!=other.mccnt) return _false("mccnt");
if (this.mcnt!=other.mcnt) return _false("mcnt");
if ((this.name==null)?(other.name!=null):!this.name.equals(other.name))
return _false("name");
if ((this.location==null)?(other.location!=null):!this.location.equals(other.location))
return _false("location");
if ((this.creator==null)?(other.creator!=null):!this.creator.equals(other.creator))
return _false("creator");
if ((this.site==null)?(other.site!=null):!this.site.equals(other.site))
return _false("site");
if (this.keywords!=other.keywords&&(this.keywords==null||!this.keywords.equals(other.keywords)))
return _false("keywords");
return true;
}
@Override
public int hashCode()
{
int hash=super.hashCode();
hash=89*hash+this.version;
hash=89*hash+this.minit;
hash=89*hash+this.maxit;
hash=89*hash+(int)(this.numit^(this.numit>>>32));
hash=89*hash+this.time;
hash=89*hash+this.efftime;
hash=89*hash+(int)(this.creattime^(this.creattime>>>32));
hash=89*hash+(int)(this.calctime^(this.calctime>>>32));
hash=89*hash+(int)(this.imgtime^(this.imgtime>>>32));
hash=89*hash+this.usedlimit;
hash=89*hash+(int)(this.mccnt^(this.mccnt>>>32));
hash=89*hash+(int)(this.mcnt^(this.mcnt>>>32));
hash=89*hash+(this.name!=null?this.name.hashCode():0);
hash=89*hash+(this.location!=null?this.location.hashCode():0);
hash=89*hash+(this.creator!=null?this.creator.hashCode():0);
hash=89*hash+(this.site!=null?this.site.hashCode():0);
hash=89*hash+(this.keywords!=null?this.keywords.hashCode():0);
return hash;
}
}