/*

      JavaScript Validation for the "Recommend Book" Form
	
	    	    	by John Walker
			 October MMI
			 
*/

/*  CANON_ISBN  --  Convert ISBN to canonical form, deleting
                    punctuation and converting any letters to
                    upper case.  Note that many forms of invalid
                    ISBNs will be passed by this code; use
                    is_ISBN_valid to check a canonical value.  */

function canon_isbn(s)
{
    var cs = s.toUpperCase(), n, ch, ocs = "";
    for (n = 0; n < cs.length; n++) {
        ch = cs.charAt(n);
        if ((ch >= '0' && (ch <= '9')) || ((ch >= 'A') && (ch <= 'Z'))) {
            ocs += ch;
        }
    }
    return ocs;
}

/*  IS_ISBN_13_CHECKSUM_VALID  --  Compute and check ISBN-13 checksum, given
                            	   ISBN-13 in canonical form.  The ISBN-13
				   checksum is computed by multiplying the
				   12 digits by alternating factors of 1 and
				   3, summing the products, then subtracting
				   the sum modulo 10 from 10.  */


function is_isbn_13_checksum_valid(s)
{
    var checksum = 0, n, v, c, f = 1;
    
    if (s.length != 13) {
//      dump("ISBN-13 err", "Bad length");
        return false;
    }
    for (n = 0; n < s.length; n++) {
        c = s.charAt(n);
        if ((c >= '0') && (c <= '9')) {
            v = c - '0';
        } else {
//          dump("ISBN-13 err", "Invalid character");
        }
        checksum += f * v;
	f = (f + 2) & 3;
    }
    checksum %= 10;

    return (checksum == 0);
}

/*  IS_ISBN_CHECKSUM_VALID  --  Compute and check ISBN checksum, given
                                ISBN in canonical form.  */


function is_isbn_checksum_valid(s)
{
    var checksum = 0, n, v, c;
    
    if (s.length == 13) {
    	return is_isbn_13_checksum_valid(s);
    }

    if (s.length != 10) {
//      dump("ISBN err", "Bad length");
        return false;
    }
    for (n = 0; n < s.length; n++) {
        c = s.charAt(n);
        if ((c >= '0') && (c <= '9')) {
            v = c - '0';
        } else if (c == 'X') {
            if (n != 9) {
//              dump("ISBN err", "X not last character");
                return false;
            }
            v = 10;
        } else {
//          dump("ISBN err", "Invalid character");
        }
        checksum += (10 - n) * v;
    }
    checksum %= 11;
    return (checksum == 0);
}

/*  TRIM  -- Trim leading and trailing blanks from a string.  */

function trim(s)
{
    var first, last, fnb = false;

    for (n = 0; n < s.length; n++) {
        if (s.charAt(n) != ' ') {
            if (!fnb) {
                first = n;
                fnb = true;
            }
            last = n;
        }
    }
    if (fnb) {
        return(s.substring(first, last + 1));
    } else {
        return "";
    }
}

/*  recommendBook

    This function is invoked by an onSubmit attribute of the
    book recommendation form.  It validates the field entries,
    confirms that the ISBN entered has a valid checksum, and
    requires the user to either enter a title and author or
    an ISBN (or both).  Validation is purely advisory--if
    the browser does not support JavaScript or it's disabled,
    the form will be submitted anyway and it's up to the
    CGI script to validate the contents and proceed accordingly.
    
    The argument is the form which invoked the function, permitting
    you to have multiple recommendation forms in one document.
    You can use "this" to specify the form in the function call,
    for example:
    
    	<form name="recommend"
	      onSubmit="return recommendBook(this);"
	      method="POST" action="/cgi-bin/RecommendBook.pl">
    
*/

function recommendBook(f)
{
    var ctitle, cauthor, cisbn, isbnok = false;

    ctitle = trim(f.title.value);
    cauthor = trim(f.author.value);
    cisbn = canon_isbn(document.recommend.isbn.value);

    if (cisbn.length > 0) {
        isbnok = is_isbn_checksum_valid(cisbn);
        if (!isbnok) {
            alert("The ISBN is erroneous (bad check digit)." +
	    	  "\nPlease verify and re-submit.  Thank you.");
            return false;
        }
    }

    /*  If a valid ISBN was given, the title and author fields
        are optional.  If no ISBN was supplied, require the title
        and author to be present.  */

    if (!isbnok && ((cauthor == "") || (ctitle == ""))) {
        alert("Please specify either the title and author\nor the ISBN for the book.");
        return false;
    }

    /*  Return true to proceed with recommendation, false to
        reject recommendation due to entry error.  */

    return true;
}

