var len=new Array(9,7,9,12,12);
var nom=new Array("ISBN-10","ISSN","ISMN","EAN","ISBN-13");
var Mpubpref=new Array(3,4,4,4,5,5,5,6,6,7);
var chstr=new Array(300);

// data obtained from http://www.isbn-international.org/en/identifiers/List-of-Ranges.pdf

chstr[0]="00,200,7000,85000,900000,9500000,an English speaking area"; // English
chstr[1]="00,100,4000,55000,869800,9990000,an English speaking area"; // English - last bit not set in stone, may be 1 digit less
chstr[2]="00,200,35000,400,7000,84000,900000,9500000,a French speaking area"; // French
chstr[3]="00,030,0340,03700,04,200,7000,85000,900000,9500000,a German speaking area"; // German
chstr[4]="00,200,7000,85000,900000,9500000,Japan"; // Japan
chstr[5]="00,200,7000,85000,9000000,91000,9200,93000,9500,98000,9900000,the Russian Federation"; // Russia
chstr[7]="00,100,5000,80000,900000,China"; // China
chstr[10]="00,200,7000,85000,900000,Czech Republic or Slovakia"; // Czechoslovakia
chstr[11]="00,200,7000,85000,900000,India"; // India - also has 93 but undefined
chstr[12]="00,200,7000,85000,990000,Norway"; // Norway
chstr[13]="00,200,60000,7000,85000,900000,Poland"; // Poland
chstr[14]="00,200,7000,85000,9000,920000,92400,930000,95000,9700,Spain"; // Spain
chstr[15]="00,200,7000,85000,900000,98000,Brazil"; // Brazil
chstr[16]="00,300,7000,80000,900000,a former Yugoslav republic"; // Yugoslavia
chstr[17]="00,400,7000,85000,970000,Denmark"; // Denmark
chstr[18]="00,200,6000,85000,900000,Italy or Italian-speaking Switzerland"; // Italian
chstr[19]="00,250,5500,85000,950000,Korea"; // Korea
chstr[20]="00,200,5000,70000,800000,8500,900000,940000,the Netherlands or Flemish-speaking Belgium"; // Belgium, Netherlands
chstr[21]="0,20,500,7000,85000,Sweden"; // Sweden
chstr[22]="0,60,800,9000,95000,990000,an international publisher"; // Unesco
chstr[23]="India";
chstr[50]="00,500,9000,99000,Argentina"; // Argentina
chstr[51]="0,20,550,8900,95000,Finland"; // Finland
chstr[52]="00,200,5000,60,6600,67000,7000,89,9500,99000,Finland"; // Finland
chstr[53]="0,10,150,6000,95000,Croatia"; // Croatia
chstr[54]="00,300,8000,90000,9300,Bulgaria"; // Bulgaria
chstr[55]="0,1000,20,550,8000,95000,Sri Lanka"; // Sri Lanka
chstr[56]="00,200,7000,Chile"; // Chile
chstr[57]="00,0300,05,2000,21,28000,31,440,8200,97000,Taiwan"; // Taiwan
chstr[58]="00,600,8000,95000,Colombia"; // Colombia
chstr[59]="00,200,7000,Cuba"; // Cuba
chstr[60]="00,200,6600,690,85000,Greece"; // Greece
chstr[61]="00,200,6000,90000,Slovenia"; // Slovenia
chstr[62]="00,200,7000,85000,8700,900,Hong Kong"; // Hong Kong
chstr[63]="00,200,7000,85000,9000,Hungary"; // Hungary
chstr[64]="00,300,5500,90000,Iran"; // Iran
chstr[65]="00,19,200,7000,90000,Israel"; // Israel
chstr[66]="00,300,7000,90000,Ukraine"; // Ukraine
chstr[67]="0,60,900,9900,99900,Malaysia"; // Malaysia
chstr[68]="01,400,5000,800,Mexico"; // Mexico - don't know what happens after 899
chstr[69]="0,20,400,8000,Pakistan"; // Pakistan
chstr[70]="01,600,9000,91000,9700,Mexico"; // Mexico
chstr[71]="000,02,0300,06,10,500,8500,91000,the Philippines"; // Philippines
chstr[72]="0,20,550,8000,95000,Portugal"; // Portugal
chstr[73]="0,20,550,7700,85000,9000,95000,Romania"; // Romania
chstr[74]="00,200,700,85000,90000,9500,Thailand"; // Thailand
chstr[75]="00,250,6000,92000,Turkey"; // Turkey
chstr[76]="0,40,600,8000,95000,the Caribbean Community"; // Caribbean
chstr[77]="00,200,5000,700,Egypt"; // Egypt
chstr[78]="000,2000,30000,8000,900,Nigeria"; // Nigeria
chstr[79]="0,20,3000,400,8000,95000,Indonesia"; // Indonesia
chstr[80]="00,200,6000,Venezuela"; // Venezuela
chstr[81]="00,200,3000,Singapore"; // Singapore
chstr[82]="00,100,70,9000,the South Pacific"; // South Pacific
chstr[83]="00,020,2000,40000,50,800,9000,99000,Malaysia"; // Malaysia
chstr[84]="00,400,8000,90000,Bangladesh"; // Bangladesh
chstr[85]="00,400,6000,90000,Belarus"; // Belarus
chstr[86]="00,120,5600,80000,Taiwan";
chstr[87]="00,1000,20000,30,500,9000,95000,Argentina"; // Argentina
chstr[88]="00,200,8000,97000,Hong Kong";
chstr[89]="0,20,550,8000,95000,Portugal";
chstr[145]="00,400,8500,Dominican Republic"; // 9945
chstr[146]="0,20,400,9000,Korea (P.D.R.)";
chstr[147]="0,20,800,Algeria";
chstr[148]="00,400,8500,United Arab Emirates";
chstr[149]="0,10,400,9000,Estonia";
chstr[150]="Palestine";
chstr[151]="00,400,8500,Kosova";
chstr[152]="0,20,400,8000,Azerbaijan";
chstr[153]="0,10,400,60,9000,Lebanon";
chstr[154]="0,20,400,8000,Morocco"; // Morocco
chstr[155]="00,400,9300,Lithuania"; // Lithuania
chstr[156]="0,10,400,9000,Cameroun"; // Cameroun
chstr[157]="00,400,8500,Jordan"; // Jordan
chstr[158]="0,10,500,9000,Bosnia and Herzegovina"; // Bosnia
chstr[159]="0,20,800,9500,Libya";
chstr[160]="00,600,9000,Saudi Arabia"; // Saudi Arabia
chstr[161]="0,30,700,9500,Algeria"; // Algeria
chstr[162]="00,5500,56,600,8500,Panama"; // Panama
chstr[163]="0,30,550,7500,Cyprus"; // Cyprus
chstr[164]="0,70,950,Ghana"; // Ghana
chstr[165]="00,400,9000,Kazakhstan"; // Kazakstan
chstr[166]="00,7000,750,9600,Kenya"; // Kenya
chstr[167]="00,400,9000,Kyrgyzstan"; // Kyrgyzstan
chstr[168]="00,500,9400,Costa Rica"; // Costa Rica
chstr[170]="00,400,9000,Uganda";
chstr[171]="0,60,900,9900,Singapore";
chstr[172]="00,1,200,2500,30,600,9000,Peru";
chstr[173]="0,10,700,9700,Tunisia";
chstr[174]="0,30,550,7500,95,Uruguay";
chstr[175]="0,50,900,9500,Moldova (Republic)";
chstr[176]="0,60,900,9990,Tanzania";
chstr[177]="00,900,9900,Costa Rica";
chstr[178]="00,300,40,950,9900,Ecuador";
chstr[179]="0,50,760,9000,Iceland";
chstr[180]="0,40,900,9900,Papua New Guinea";
chstr[181]="00,100,1600,20,800,9500,Morocco";
chstr[182]="00,800,9900,Zambia";
chstr[183]="80,950,9900,Gambia"; // don't know what happens before 80
chstr[184]="00,500,9000,Latvia";
chstr[185]="0,50,800,9000,Estonia";
chstr[186]="00,400,9000,940,97,Lithuania";
chstr[187]="00,400,8800,Tanzania";
chstr[188]="0,30,550,7500,Ghana";
chstr[189]="0,100,2000,30,600,9500,Macedonia";
chstr[201]="00,500,80,Bahrain";
chstr[202]="Gabon";
chstr[203]="0,20,900,Mauritius";
chstr[204]="0,60,900,Netherlands Antilles";
chstr[205]="Bolivia";
chstr[206]="0,30,600,Kuwait";
chstr[208]="0,10,900,Malawi";
chstr[209]="0,40,950,Malta";
chstr[210]="0,30,900,Sierra Leone";
chstr[211]="00,600,Lesotho";
chstr[212]="0,500,60,900,Botswana";
chstr[213]="0,30,600,Andorra";
chstr[214]="0,50,900,Suriname";
chstr[215]="0,50,800,Maldives";
chstr[216]="0,30,700,Namibia";
chstr[217]="0,30,900,Brunei Darussalam";
chstr[218]="0,40,900,Faroe Islands";
chstr[219]="0,40,900,Benin";
chstr[220]="0,50,900,Andorra";
chstr[221]="0,20,700,8,90,Qatar";
chstr[222]="0,40,700,Guatemala";
chstr[223]="0,20,800,El Salvador";
chstr[224]="0,30,800,Nicaragua";
chstr[225]="0,40,800,Paraguay";
chstr[226]="0,10,600,Honduras";
chstr[227]="0,30,600,Albania";
chstr[228]="0,10,800,Georgia";
chstr[229]="Mongolia";
chstr[230]="0,50,800,Armenia";
chstr[231]="0,50,800,Seychelles";
chstr[232]="0,10,600,7,80,Malta";
chstr[233]="0,30,600,Nepal";
chstr[234]="0,20,800,Dominican Republic";
chstr[235]="0,30,600,8,90,Haiti";
chstr[236]="0,10,600,Bhutan";
chstr[237]="0,20,600,Macau";
chstr[238]="0,30,600,Srpska";
chstr[239]="0,60,900,Guatemala";
chstr[240]="0,10,700,Georgia";
chstr[241]="0,30,900,Armenia";
chstr[242]="0,50,800,Sudan";
chstr[243]="0,30,600,Albania";
chstr[244]="0,50,800,Ethiopia";
chstr[246]="0,30,600,Nepal";

function checkISBN() {
if (document.form0.yourinput.value != "") {
  var reply1="";
  var reply2="";
  var reply3="";
  var isbn=getISBN(document.form0.yourinput.value);
  var type=gettype(isbn);
  if (valid(isbn,type)) {
    var ckdig=getckdig(isbn);
    reply1="This is an "+nom[type];
    if (type==0 && country(isbn)!="") reply1+=" from "+country(isbn);
    reply1+=".  The check digit is ";
    if (isbn.length>len[type]) {
      var cd=""+ckdig;
      if (isbn.charAt(len[type])!=cd) reply1+="incorrect: it should be "+ckdig+".";
      else reply1+="correct.";
    }
    else reply1+=ckdig+".";
    reply2="The full "+nom[type]+" is "+fullnum(isbn)+".";
    if (type==0) { // ISBN-10
      reply3="The ISBN-13 is "+fullnum("978"+isbn.substring(0,9))+".";
    }
    else if (type==3) { //EAN
      if (isbn.substring(0,3)=="977") reply3="It is for a serial publication with ISSN "+fullnum(isbn.substring(3,10))+".";
      else if (isbn.substring(0,4)=="9790") reply3="It is for a piece of music with ISMN "+fullnum("M"+isbn.substring(4,12))+".";
    }
    else if (type==4) { //ISBN-13
      if (isbn.substring(0,3)=="978") {
        reply3="It is for a book";
        if (country(isbn.substring(3,12))!="") reply3+=" from "+country(isbn.substring(3,12));
        reply3+=" with ISBN-10 "+fullnum(isbn.substring(3,12))+".";
      }
      else {
        reply3="13-digit ISBNs are a new standard from 2007, which I don't know any more about yet.";
      }
    }
  }
  else {
    if (isbn.length>13 && isbn.substring(0,3)=="977" && valid (isbn.substring(0,13),3)) {
      ean=isbn.substring(0,13);
      if (ean==fullnum(ean)) {
        reply1=ean+" is an EAN. The check digit is correct.";
        reply2="It is for a serial publication with ISSN "+fullnum(isbn.substring(3,10))+", issue number "+isbn.substring(13,isbn.length)+".";
        }
      else reply1="You have typed in too much, too little, or letters instead of numbers.";
      }
    else reply1="You have typed in too much, too little, or letters instead of numbers.";
    }
  if (reply3=="") {
    document.form1.rep1.value=reply1;
    document.form1.rep2.value=reply2;
    }
  else {
    document.form1.rep1.value=reply1+"  "+reply2;
    document.form1.rep2.value=reply3;
    }
  }
return false;
}

function gettype(num) {
var x=5; // invalid default
var l=num.length;
var c=""+num.charAt(0);
  if (l==9 || l==10) x=0; // ISBN
  if (l==7 || l==8) x=1; // ISSN
  if (x==0 && c=="M") x=2; // ISMN
  if (l==12 || l==13) x=3; // EAN
  if (x==3 && (num.substring(0,3)=="978" || (num.substring(0,3)=="979" && num.charAt(3)!="0"))) x=4; // ISBN-13
return x;
}

function getckdig(num) {
var t=gettype(num);
var cksum=0;
if (t<2) {
  for (x=0;x<len[t];x++) cksum+=(1+len[t]-x)*num.charAt(x);
  var ckdig=(1100-cksum)%11;
  if (ckdig==10) ckdig="X";
  }
else {
  if (t==2) cksum=9;
  if (t==4) t=3;
  for (x=3-t;x<len[t];x++) cksum+=(3-2*((x+t)%2))*num.charAt(x);
  var ckdig=(1000-cksum)%10;
  }
return ckdig;
}

function fullnum(num) {
var numstr=num.substring(0,len[gettype(num)])+getckdig(num);
return hyphenate(numstr);
}

function country(str) {
  var country="";
  var ranges=chstr[shp(prefix(str))];
  if (ranges!=null) {
    var comma=ranges.lastIndexOf(",");
    if (isNaN(ranges.charAt[comma+1])) country=ranges.substring(comma+1);
  }
  return country;
}

function hyphenate(str) {
var ourstr="";
if (gettype(str)==2) {
  var breaker=1+Mpubpref[str.charAt(1)];
  ourstr="M-"+str.substring(1,breaker)+"-"+str.substring(breaker,9)+"-"+str.charAt(9);
  }
if (gettype(str)==0) {
  var pref=prefix(str);
  var breaker=0;
  var pl=pref.length;
  if (chstr[shp(pref)]!=null) {
    var bits=chstr[shp(pref)].split(",");
    for (i=0; bits[i]!=null; i++) {
      var tl=bits[i].length;
      if (str.substring(pl,pl+tl)>=bits[i]) breaker=pl+tl;
    }
  }
  if (breaker>0) ourstr=pref+"-"+str.substring(pl,breaker)+"-"+str.substring(breaker,9)+"-"+str.charAt(9);
  else if (pref!="") ourstr=pref+"-"+str.substring(pl)+" (hyphenation undocumented)";
  else ourstr=str+" (hyphenation undocumented)";
}
if (gettype(str)==1) ourstr=str.substring(0,4)+"-"+str.substring(4,8);
if (gettype(str)==3) ourstr=str;
if (gettype(str)==4) ourstr=str.substring(0,3)+"-"+hyphenate(str.substring(3,13));
return ourstr;
}

function prefix(str) {
var x="";
if (str.charAt(0)<8) x=str.charAt(0);
if (str.substring(0,2)>"79" && str.substring(0,2)<"94") x=str.substring(0,2);
if (str.substring(0,2)>"94" && str.substring(0,2)<"99") x=str.substring(0,3);
if (str.substring(0,3)>"989" && str.substring(0,3)<"999") x=str.substring(0,4);
if (str.substring(0,3)=="999") x=str.substring(0,5);
return x;
}

function shp(pref) {
if (pref=="") return 25; // an unused shp
if (pref<8) return pref;
if (pref<99) return pref-70; // 80-93 -> 10-23
if (pref<999) return pref-900; // 950-989 -> 50-89
if (pref<9999) return pref-9800; // 9900-9989 -> 100-189
return pref-99700; // 99900-99999 -> 200-299
}

function valid(num,type) {
var v=(type<5);
for (x=0; x<len[type]; x++) {
  var c=""+num.charAt(x);
  if ((x>0 || c!="M" || type!=2) && (c<"0" || c>"9")) v=0;
  }
return v;
}

function getISBN(istring) {
var i="";
for (x=0; x<istring.length; x++) {
  var j=istring.charAt(x);
  if (j>="0" && j<="9") i+=j;
  else {
    if (j=="x" || j=="X") i+="X";
    else if (j=="m" || j=="M") i+="M";
    }
  }
return i;
}

function clearMyBits() {
document.form1.reset();
}

function listISBNs() {
  nw=window.open("","newW");
  nw.document.write("<h3>ISBNs which are correctly hyphenated</h3>");
  nw.document.write("<p>Data last updated 16 Dec 2004, obtained from <a href=http://www.isbn-international.org/en/identifiers.html>The International ISBN Agency</a>.</p>");
  nw.document.write("<table border><tr><th>Prefix</th><th>Country of origin</th><th>Publisher code ranges</th></tr>");
  for (var i=0; i<300; i++) {
    if (chstr[i]!=null) {
      var pref=i;
      if (pref>199) pref+=99700;
      else if (pref>99) pref+=9800;
      else if (pref>25) pref+=900;
      else if (pref>9) pref+=70;
      pref=""+pref;
      nw.document.write("<tr><td>",pref,"</td><td>",country(pref),"</td><td>");
      var bits=chstr[i].split(",");
      for (var j=0; bits[j]!=null; j++) {
        if (bits[j+1]!=null) {
          nw.document.write(bits[j],"-");
          if (isNaN(bits[j+1])) for (var k=0; k<bits[j].length; k++) nw.document.write(9);
          else {
            var k=""+(bits[j+1]-1);
            if (k.length>bits[j].length) k=k.substring(0,bits[j].length);
            else while (k.length<bits[j].length) k+="9";
            nw.document.write(k+", ");
          }
        }
      }
      nw.document.write("</td></tr>");
    }
  }
  nw.document.close();
}
