/* * [Book.java] * * Summary: Implements Book Macro to create references for a book to various book stores. * * Copyright: (c) 2007-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.9 2007-03-20 new code for Powell's, Barnes and Noble, * AMAZON.com, AMAZON.ca, AMAZON.co.uk, AMAZON.ca, AMAZON.de * 2.0 2007-03-24 uses buildGenericAmazon, adds flags, AMAZON.fr. * 2.1 2011-09-28 add AMAZON.es and AMAZON.it. Drop impression counters. new style links. * 2.2 2011-09-30 add eBook support in Safari and Sony * 2.3 2011-10-17 add support for audio * 2.4 2014-03-21 drop Sony * 2.5 2016-07-09 allow isbn fields to be comma lists */ package com.mindprod.stores; import com.mindprod.common18.BigDate; import com.mindprod.common18.EIO; import com.mindprod.common18.ST; import com.mindprod.fastcat.FastCat; import com.mindprod.htmlmacros.macro.Born; import com.mindprod.htmlmacros.macro.CountryFlag; import com.mindprod.htmlmacros.macro.GoogleCannedSearch; import com.mindprod.htmlmacros.macro.Macro; import com.mindprod.htmlmacros.support.BuildImage; import com.mindprod.htmlmacros.support.ImageAlignment; import com.mindprod.htmlmacros.support.Tools; import com.mindprod.hunkio.HunkIO; import com.mindprod.isbn.ISBNValidate; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.regex.Pattern; import static com.mindprod.htmlmacros.macro.Global.configuration; import static com.mindprod.stores.BStore.*; import static com.mindprod.stores.StockStatus.INSTOCK; import static java.lang.System.*; /** * Implements Book Macro to create references for a book to various book stores. *

* Expands HTML Book macro, formats data in a table. expand is called by both com.mindprod.htmlmacros.Book to regenerate * html from \n" ); return sb.toString(); }// /method /** * get the preferred ISBNs for this store to sell this book * * @param bookStore which online store * * @return array of ISBNsu */ private String[] getPreferredISBNs( BStore bookstore ) { if ( bookstore.isOnlyEbooks() ) { return preferredEbookISBNs; } else { return preferredPaperISBNs; } } /** * is this book stocked somewhere? * * @param isbn13 main isbn, not a commolist * @param eBook eBook isbn * * @return true if book in stock in at least one bookstore */ private boolean isStockedSomewhere( final String isbn13, final String title ) { assert !isbn13.contains( "," ) : "primary isbn " + isbn13 + " contains comma."; boolean stockedSomewhere = false; for ( String isbn : preferredPaperISBNs ) { for ( BStore bookStore : BStore.values() ) { if ( !bookStore.isAlive() ) { continue; } if ( bookStore.getProductStatus( isbn, true ) == INSTOCK ) { return true; } } } // report unstocked books, unless marked as rare in config if ( !configuration.isProductRare( isbn13 ) ) { // isbn13 is a single field reportUnstockedProduct( "book", isbn13, EIO.getCanOrAbsPath( fileBeingProcessed ), title ); } return false; }// /method /** * Insert optional country flag on left of link. *

* * @param onRight true if inserting on right side of table. * @param flag CountryFlag country. * * @return HTML to display the flag */ private String leadingCountryFlag( boolean onRight, CountryFlag flag ) { return onRight ? "" : "" + flag.getFlagRef( fileBeingDistributed ) + "\n"; }// /method /** * Insert optional country flag on right of link. * * @param onRight true if inserting on right side of table. * @param flag CountryFlag country. * * @return HTML to display the flag */ private String trailingCountryFlag( boolean onRight, CountryFlag flag ) { return onRight ? "\n" + flag.getFlagRef( fileBeingDistributed ) + "\n" : "\n"; }// /method /** * Generate macro expansion for Book macro. primarily parse list of parms. * * @param parms parsed params for the macro. parms typically look like this: Parms may be in any order and already entity-encoded. * @param quiet true if want output suppressed. * @param verbose @return expanded text */ public String expandMacro( String[] parms, final boolean quiet, final boolean verbose ) { if ( parms.length < 6 ) { throw new IllegalArgumentException( USAGE ); } // must have even number of parms if ( ( parms.length & 1 ) != 0 ) { throw new IllegalArgumentException( "Book macro syntax error: must have parm=value pairs" ); } // set defaults String audio = ""; String author = "anonymous"; String birth = ""; String death = ""; String eBook = ""; String hardcover13 = ""; String isbn13 = ""; String kindle = ""; String notes = ""; String paperback13 = ""; String published = ""; String publisher = ""; String title = "unknown title"; String webbook = ""; // extract data from parms for ( int i = 0; i < parms.length; i += 2 ) { String name = parms[ i ]; String value = parms[ i + 1 ]; switch ( name ) { case "isbn": ISBNValidate.ensureISBN13Valid( value ); isbn13 = value; break; case "paperback": paperback13 = value; break; case "hardcover": hardcover13 = value; break; case "kindle": kindle = value.toUpperCase();/* e.g. -000OZ0N5I */ break; case "ebook": eBook = value; break; case "audio": audio = value; break; case "title": title = value; break; case "author": author = value; break; case "birth": birth = value; break; case "death": death = value; break; case "notes": notes = value; break; case "price": // ignore it. AMAZON does not want us displaying prices, especially out of date prices. Further Each // vendor has a different price. break; case "publisher": publisher = value; break; case "published": published = value; switch ( published.length() ) { case 1: if ( !published.equals( "?" ) ) { throw new IllegalArgumentException( "[published] date must be ? for unknown" ); } break; case 10: if ( !BigDate.isValid( published ) ) { throw new IllegalArgumentException( "[published] date must be a valid date of form yyyy-mm-dd" ); } break; case 7: if ( !BigDate.isValid( published + "-01" ) ) { throw new IllegalArgumentException( "[published] date must be a valid date of form " + "yyyy-mm" ); } break; case 4: if ( !BigDate.isValid( published + "-01-01" ) ) { throw new IllegalArgumentException( "[published] date must be a valid date of form yyyy" ); } break; default: throw new IllegalArgumentException( "[published] date must be a valid date of form " + "yyyy-mm-dd" ); } break; case "webbook": ISBNValidate.ensureISBN13Valid( value ); webbook = value.toUpperCase(); break; default: throw new IllegalArgumentException( "Book macro syntax error: unknown parm: [" + name + "]" ); } } // end for if ( isbn13.length() == 0 ) { if ( paperback13.length() > 0 ) { isbn13 = paperback13; } else if ( hardcover13.length() > 0 ) { isbn13 = hardcover13; } else { throw new IllegalArgumentException( "no ISBN specified by [isbn], [paperback] or [hardcover]" ); } } if ( !( paperback13.length() > 0 || hardcover13.length() > 0 ) ) { throw new IllegalArgumentException( "Book macro must have either [paperback] or [hardcover] or both" ); } if ( !( paperback13.contains( isbn13 ) || hardcover13.contains( isbn13 ) ) ) { throw new IllegalArgumentException( "Book macro [isbn] must match either [paperback] or [hardcover]" ); } // generate the HTML to refer this book. return expand( isbn13, paperback13, hardcover13, kindle, eBook, webbook, audio, title, publisher, published, author, birth, death, notes ); }// /method // /methods } // end Book /** * used to allow methods to return 2 or 3 values */ class BestResult { /** * constructor */ final OnlineStore onlineStore; final String product; final StockStatus stockStatus; BestResult( OnlineStore onlineStore, String product, StockStatus stockStatus ) { this.onlineStore = onlineStore; this.product = product; this.stockStatus = stockStatus; } }