Index: cpp/frams/genetics/geno.cpp
===================================================================
--- cpp/frams/genetics/geno.cpp	(revision 145)
+++ cpp/frams/genetics/geno.cpp	(revision 150)
@@ -8,257 +8,265 @@
 
 SListTempl<GenoValidator*> Geno::validators;
-GenoConvManager *Geno::converters=NULL;
-
-void Geno::init(const SString& genstring,char genformat,const SString& genname,const SString& comment)
-{
-refcount=1;
-owner=0;
-f0gen=0;
-mapinshift=0;
-mapoutshift=0;
-isvalid=-1;
-SString gencopy(genstring);
-if (genformat==-1)
+GenoConvManager *Geno::converters = NULL;
+
+void Geno::init(const SString& genstring, char genformat, const SString& genname, const SString& comment)
+{
+	refcount = 1;
+	owner = 0;
+	f0gen = 0;
+	mapinshift = 0;
+	mapoutshift = 0;
+	isvalid = -1;
+	SString gencopy(genstring);
+	if (genformat == -1)
 	{ // unknown format
-	genformat='1';
-	if (genstring.charAt(0)=='/')
+		genformat = '1';
+		if (genstring.charAt(0) == '/')
 		{
-		int end;
-		SString newcomment;
-		switch(genstring.charAt(1))
+			int end;
+			SString newcomment;
+			switch (genstring.charAt(1))
 			{
 			case '/':
-				genformat=genstring.charAt(2);
-				if ((end=genstring.indexOf('\n'))>=0)
-					{
-					newcomment=genstring.substr(2,end-2);
-					gencopy=genstring.substr(end+1);
-					mapinshift=end+1;
-					}
+				genformat = genstring.charAt(2);
+				if ((end = genstring.indexOf('\n')) >= 0)
+				{
+					newcomment = genstring.substr(2, end - 2);
+					gencopy = genstring.substr(end + 1);
+					mapinshift = end + 1;
+				}
 				else
-					{
-					gencopy=0;
-					mapinshift=genstring.len();
-					}
+				{
+					gencopy = 0;
+					mapinshift = genstring.len();
+				}
 				break;
 			case '*':
-				genformat=genstring.charAt(2);
-				if ((end=genstring.indexOf("*/"))>=0)
-					{
-					newcomment=genstring.substr(2,end-2);
-					gencopy=genstring.substr(end+2);
-					mapinshift=end+2;
-					}
+				genformat = genstring.charAt(2);
+				if ((end = genstring.indexOf("*/")) >= 0)
+				{
+					newcomment = genstring.substr(2, end - 2);
+					gencopy = genstring.substr(end + 2);
+					mapinshift = end + 2;
+				}
 				else
-					{
-					gencopy=0;
-					mapinshift=genstring.len();
-					}
+				{
+					gencopy = 0;
+					mapinshift = genstring.len();
+				}
 				break;
 			}
-		if (newcomment.len()>0)
+			if (newcomment.len() > 0)
 			{
-			SString token; int pos=0;
-			if (newcomment.getNextToken(pos,token,';'))
-			if (newcomment.getNextToken(pos,token,';'))
-				{
-				if (token.len()) txt=token;
-			if (newcomment.getNextToken(pos,token,';'))
-				if (token.len()) name=token;
-				}
+				SString token; int pos = 0;
+				if (newcomment.getNextToken(pos, token, ';'))
+					if (newcomment.getNextToken(pos, token, ';'))
+					{
+						if (token.len()) txt = token;
+						if (newcomment.getNextToken(pos, token, ';'))
+							if (token.len()) name = token;
+					}
 			}
 		}
 	}
 
-gen=gencopy;
-format=genformat;
-if (!name.len()) name=genname;
-if (!txt.len()) txt=comment;
-multiline=(strchr((const char*)gen,'\n')!=0);
-// mapoutshift...?
+	gen = gencopy;
+	format = genformat;
+	if (!name.len()) name = genname;
+	if (!txt.len()) txt = comment;
+	multiline = (strchr((const char*)gen, '\n') != 0);
+	// mapoutshift...?
 }
 
 void Geno::freeF0()
 {
-if (f0gen) {delete f0gen; f0gen=0;}
-}
-
-Geno::Geno(const char *genstring,char genformat,const char *genname,const char *comment)
-{
-init(SString(genstring),genformat,SString(genname),SString(comment));
-}
-
-Geno::Geno(const SString& genstring,char genformat,const SString& genname,const SString& comment)
-{
-init(genstring,genformat,genname,comment);
+	if (f0gen) { delete f0gen; f0gen = 0; }
+}
+
+Geno::Geno(const char *genstring, char genformat, const char *genname, const char *comment)
+{
+	init(SString(genstring), genformat, SString(genname), SString(comment));
+}
+
+Geno::Geno(const SString& genstring, char genformat, const SString& genname, const SString& comment)
+{
+	init(genstring, genformat, genname, comment);
 }
 
 Geno::Geno(const Geno& src)
-	:gen(src.gen),name(src.name),format(src.format),txt(src.txt),isvalid(src.isvalid),
-	 f0gen(0),mapinshift(src.mapinshift),mapoutshift(src.mapinshift),
-	 multiline(src.multiline),owner(0)
-{f0gen=src.f0gen?new Geno(*src.f0gen):0; refcount=1;}
+:gen(src.gen), name(src.name), format(src.format), txt(src.txt), isvalid(src.isvalid),
+f0gen(0), mapinshift(src.mapinshift), mapoutshift(src.mapinshift),
+multiline(src.multiline), owner(0)
+{
+	f0gen = src.f0gen ? new Geno(*src.f0gen) : 0; refcount = 1;
+}
 
 void Geno::operator=(const Geno& src)
 {
-freeF0();
-gen=src.gen;
-name=src.name;
-format=src.format;
-txt=src.txt;
-isvalid=src.isvalid;
-mapinshift=src.mapinshift;
-mapoutshift=src.mapinshift;
-multiline=src.multiline;
-f0gen=src.f0gen?new Geno(*src.f0gen):0;
-owner=0;
+	freeF0();
+	gen = src.gen;
+	name = src.name;
+	format = src.format;
+	txt = src.txt;
+	isvalid = src.isvalid;
+	mapinshift = src.mapinshift;
+	mapoutshift = src.mapinshift;
+	multiline = src.multiline;
+	f0gen = src.f0gen ? new Geno(*src.f0gen) : 0;
+	owner = 0;
 }
 
 Geno::Geno(const SString& src)
 {
-init(src,-1,SString::empty(),SString::empty());
-}
-
-void Geno::setGene(const SString& g,char newformat)
-{
-gen=g;
-isvalid=-1;
-freeF0();
-if (newformat>=0) format=newformat;
+	init(src, -1, SString::empty(), SString::empty());
+}
+
+void Geno::setGene(const SString& g, char newformat)
+{
+	gen = g;
+	isvalid = -1;
+	freeF0();
+	if (newformat >= 0) format = newformat;
 }
 
 void Geno::setString(const SString& g)
 {
-freeF0();
-init(g,-1,SString::empty(),SString::empty());
+	freeF0();
+	init(g, -1, SString::empty(), SString::empty());
 }
 
 void Geno::setName(const SString& n)
 {
-name=n;
+	name = n;
 }
 
 void Geno::setComment(const SString& c)
 {
-txt=c;
+	txt = c;
 }
 
 SString Geno::toString(void) const
 {
-SString out;
-int comment=0;
-if ((format!='1')||(comment=(txt.len()||name.len())))
-	{
-	if (multiline)
-		out+="//";
+	SString out;
+	int comment = 0;
+	if ((format != '1') || (comment = (txt.len() || name.len())))
+	{
+		if (multiline)
+			out += "//";
+		else
+			out += "/*";
+		out += format;
+		if (comment)
+		{
+			if (txt.len()) { out += ";"; out += txt; }
+			if (name.len()){ out += ";"; out += name; }
+		}
+		if (multiline)
+			out += "\n";
+		else
+			out += "*/";
+	}
+	out += gen;
+	return out;
+}
+
+SString Geno::shortString(void) const
+{
+	SString out;
+	if (format != '1')
+	{
+		if (multiline)
+			out += "//";
+		else
+			out += "/*";
+		if (format == 0)
+			out += "invalid";
+		else
+			out += format;
+		if (multiline)
+			out += "\n";
+		else
+			out += "*/";
+	}
+	out += gen;
+	return out;
+}
+
+int Geno::mapGenToString(int genpos) const
+{
+	if (genpos > gen.len()) return -2;
+	if (genpos<0) return -1;
+	return mapinshift + genpos;
+}
+
+int Geno::mapStringToGen(int stringpos) const
+{
+	stringpos -= mapinshift;
+	if (stringpos>gen.len()) return -2;
+	if (stringpos < 0) return -1;
+	return stringpos;
+}
+
+SString Geno::getGene(void) const { return gen; }
+SString Geno::getName(void) const { return name; }
+char Geno::getFormat(void) const { return format; }
+SString Geno::getComment(void) const { return txt; }
+
+int ModelGenoValidator::testGenoValidity(Geno& g)
+{
+	if (g.getFormat() == '0')
+	{
+		Model mod(g);
+		return mod.isValid();
+	}
 	else
-		out+="/*";
-	out+=format;
-	if (comment)
+	{
+		bool converter_missing;
+		Geno f0geno = g.getConverted('0', NULL, &converter_missing);
+		if (converter_missing)
+			return -1;//no result
+		return f0geno.isValid();
+	}
+}
+
+void Geno::validate()
+{
+	if (isvalid >= 0) return;
+	if (gen.len() == 0) { isvalid = 0; return; }
+	FOREACH(GenoValidator*, v, validators)
+		if ((isvalid = v->testGenoValidity(*this)) >= 0)
+			return;
+	isvalid = 0;
+	FMprintf("Geno", "validate", FMLV_WARN, "Wrong configuration? No genotype validators defined for genetic format f%c.", format);
+}
+
+bool Geno::isValid(void)
+{
+	if (isvalid<0) validate();
+	return isvalid>0;
+}
+
+Geno Geno::getConverted(char otherformat, MultiMap *m, bool *converter_missing)
+{
+	if (otherformat == getFormat()) { if (converter_missing) *converter_missing = false; return *this; }
+#ifndef NO_GENOCONVMANAGER
+	if (converters)
+	{
+		if ((otherformat == '0') && (!m))
 		{
-		if (txt.len()) {out+=";";out+=txt;}
-		if (name.len()){out+=";";out+=name;}
+			if (!f0gen)
+				f0gen = new Geno(converters->convert(*this, otherformat, NULL, converter_missing));
+			return *f0gen;
 		}
-	if (multiline)
-		out+="\n";
-	else
-		out+="*/";
-	}
-out+=gen;
-return out;
-}
-
-SString Geno::shortString(void) const
-{
-SString out;
-if (format!='1')
-	{
-	if (multiline)
-		out+="//";
-	else
-		out+="/*";
-	if (format==0)
-		out+="invalid";
-	else
-		out+=format;
-	if (multiline)
-		out+="\n";
-	else
-		out+="*/";
-	}
-out+=gen;
-return out;
-}
-
-int Geno::mapGenToString(int genpos) const
-{
-if (genpos>gen.len()) return -2;
-if (genpos<0) return -1;
-return mapinshift+genpos;
-}
-
-int Geno::mapStringToGen(int stringpos) const
-{
-stringpos-=mapinshift;
-if (stringpos>gen.len()) return -2;
-if (stringpos<0) return -1;
-return stringpos;
-}
-
-SString Geno::getGene(void) const {return gen;}
-SString Geno::getName(void) const {return name;}
-char Geno::getFormat(void) const {return format;}
-SString Geno::getComment(void) const {return txt;}
-
-int ModelGenoValidator::testGenoValidity(Geno& g)
-{
-if (g.getFormat()=='0')
-	{
-	Model mod(g);
-	return mod.isValid();
-	}
-else
-	{
-	Geno f0geno=g.getConverted('0');
-	return f0geno.isValid();
-	}
-}
-
-void Geno::validate()
-{
-if (isvalid>=0) return;
-if (gen.len()==0) { isvalid=0; return; }
-FOREACH(GenoValidator*,v,validators)
-	if ((isvalid=v->testGenoValidity(*this))>=0)
-		break;
-}
-
-bool Geno::isValid(void)
-{
-if (isvalid<0) validate();
-return isvalid>0;
-}
-
-Geno Geno::getConverted(char otherformat,MultiMap *m)
-{
-if (otherformat==getFormat()) return *this;
-#ifndef NO_GENOCONVMANAGER
-if (converters)
-	{
-	if ((otherformat=='0')&&(!m))
-		{
-		if (!f0gen)
-			f0gen=new Geno(converters->convert(*this,otherformat));
-		return *f0gen;
-	}
-	else
-		return converters->convert(*this,otherformat,m);
+		else
+			return converters->convert(*this, otherformat, m, converter_missing);
 	}
 #endif
-return (otherformat==getFormat())?*this:Geno(0,0,0,"GenConvManager not available");
+	if (converter_missing) *converter_missing = true;
+	return (otherformat == getFormat()) ? *this : Geno(0, 0, 0, "GenConvManager not available");
 }
 
 Geno::~Geno()
 {
-if (f0gen) delete f0gen;
-}
+	if (f0gen) delete f0gen;
+}
