Basic structure of a site plugin
--------------------------------

Passed search parameters from the item_add.php script.  These parameters
have been configured internally by the plugin.

The plugin is requested to return a list of matching items, in some
sort of listings format, possibly with pagination.

Each row should consist of:

	URL to load matching item from the site
	title of item (including year if available)
	cover image (if available)

The total item count should also be returned, so that pagination can
be calculated.

There should be an option to widen the search if available, such as
for IMDB, so how is this accomplished.

function get_site_titles_list($HTTP_VARS, $pageno, &$last_page_no, &$items_per_page)

If the function returns a single record, then we have an exact match.

function get_title_attributes($HTTP_VARS)

This will return the $attributes array or null if the page cannot be parsed.

Suggest a table structure for site plugins, something like:

#
# Site Plugin Configuration
#
CREATE TABLE site_plugin (
	site_type		VARCHAR(10) NOT NULL,
	title			VARCHAR(50) NOT NULL,
	img				VARCHAR(255) NOT NULL,
	description		VARCHAR(255) NOT NULL,
	external_url	VARCHAR(255) NOT NULL,
	PRIMARY KEY ( site_type ),
) TYPE=MyISAM COMMENT='Site Plugin Configuration';

#
# Site Plugin Input Field
#
# This table will define the input fields generated for
# the plugin in the item_add (or item_input if we
# merge this into one location) script.
#
CREATE TABLE site_plugin_input_field (
	site_type		VARCHAR(10) NOT NULL,
	field			VARCHAR(10) NOT NULL,
	order_no		TINYINT(2) NOT NULL,
	description		VARCHAR(255) NOT NULL,
	prompt			varchar(30) default NULL,
	type			VARCHAR(10) NOT NULL DEFAULT 'text',
	value			VARCHAR(50),
	refresh_mask	VARCHAR(50),
	PRIMARY KEY ( site_type, field ),
) TYPE=MyISAM COMMENT='Site Plugin Input Field';

The 'type' can be one of 'text' or 'hidden'

The 'field' is the name of the field as will be passed to the
site plugin itself.  The site plugin will be programmed
to accept input for these field types and will if necessary
convert it to a S_ATTRIBUTE_TYPE specific to OpenDb so that
it can be correctly inserted.

NOTE: The 'refresh_mask' field can use title_mask syntax for
some simple procedural logic.  For instance, it may be useful
to have a simple value of:

{ifdef(amazonasin,{amazonasin},if(s_item_type==BOOK,{isbn},''))}

Basically this says that if amazonasin is defined use that, otherwise
if s_item_type of BOOK, then try the {isbn} value.

#
#
#
CREATE TABLE site_plugin_s_attribute_type_map (
	site_type			VARCHAR(10) NOT NULL,
	variable			VARCHAR(10) NOT NULL,
	s_item_type_group	VARCHAR(10) NOT NULL DEFAULT '*',
	s_item_type			VARCHAR(10) NOT NULL DEFAULT '*',
	s_attribute_type	VARCHAR(10) NOT NULL,
	PRIMARY KEY ( site_type, variable, s_item_type, s_item_type_group, s_attribute_type ),
) TYPE=MyISAM COMMENT='Site Plugin Attribute Type Map';

This table is used to provide mappings between the
variables a site plugin sets and those used within
Opendb.  This mapping can have a s_item_type or s_item_type_group 
context if applicable.

More than one mapping can exist for a variable, in which case
entries for each mapping will be added to the attributes
array.  For example, we might have a mapping of:

INSERT INTO site_plugin_s_attribute_type_map(site_type, variable, s_item_type_group, s_item_type, s_attribute_type)
VALUES ('amazon', 'title', '*', '*', 'ALT_TITLE');

*** WARNING ***
If any site_plugin_s_attribute_type_map records exist for a variable, the variable itself will
no longer be included in the attributes collection.  In the case of alt_title, this would mean
that 'title' is no longer being included! This is a bit of a problem, and a record would have
to be explicitly included for title:

INSERT INTO site_plugin_s_attribute_type_map(site_type, variable, s_item_type_group, s_item_type, s_attribute_type)
VALUES ('amazon', 'title', '*', 'S_TITLE');

====> This is an interesting one, because at the moment we have special variables 'title' and 'category'
for the item, when we should probably pass as s_attribute_type variables, and then let the item_input
script work out which of the attributes match the 'title' and 'category' values.

NOTE: We use '*' so that we can include s_item_type in the PK, and still try
and provide some self documentation of the code.  This relies on no s_item_type of 
'*' being used!

#
#
#
CREATE TABLE site_plugin_s_attribute_type_lookup_map (
	site_type				VARCHAR(10) NOT NULL,
	s_attribute_type		VARCHAR(10) NOT NULL,
	value					VARCHAR(50) NOT NULL,
	lookup_attribute_val	VARCHAR(50) NOT NULL
	PRIMARY KEY ( site_type, s_attribute_type, value ),
) TYPE=MyISAM COMMENT='Site Plugin Attribute Type Lookup Map';

This table provides mappings between the site plugin value and the specific
s_attribute_type_lookup.value for the specific s_attribute_type, as provided
by either the site_plugin_s_attribute_type_map or if none exist, by uppercasing
the variable assuming its the same as a S_ATTRIBUTE_TYPE.  If no mapping exists,
it gets passed straight through.

#
# This table provides any site plugin specific variable configuration,
# and a plugin should provide defaults for all such conf variables
# when installed, so that the user can correctly configure them
# if required based on the description field.
#
CREATE TABLE site_plugin_conf (
	site_type	VARCHAR(10) NOT NULL,
	name		VARCHAR(50) NOT NULL,
	description	VARCHAR(255),
	keyid			VARCHAR(50) NOT NULL DEFAULT '0',
	value		VARCHAR(255),
	PRIMARY KEY ( site_type, name, keyid ),
) TYPE=MyISAM COMMENT='Site Plugin Configuration';

The name is the name of the configuration item

When we build up the structure of all configuration items for a particular
site_type, it is possible to have multiple keyid records for a name, and these
will be structured into an array.  if the first keyid value is numeric, its
assumed to be an numeric keyid array, otherwise we assume the keyids are
alphanumeric.  Unfortunately there is no way to have more than one level
arrays, which hopefully should not be a problem, as we have provided
other site_plugin definitition tables for more complicated configuration
details.

If more than one configuration record for a name, the description field
only has to be populated for one record, if its to be a general description,
the logic inside OpenDb will read in all the entries and be sure to save
the description once and represent it in the admin tool.

Site Item Link 
--------------

The $site_item_link_rs functionality can be standardised into a table...

CREATE TABLE site_plugin_link (
	site_type		VARCHAR(10) NOT NULL,
	s_item_type_group	VARCHAR(10) NOT NULL DEFAULT '*',
	s_item_type		VARCHAR(10) NOT NULL DEFAULT '*',
	description		VARCHAR(50),
	order_no		TINYINT(2) NOT NULL,
	url			VARCHAR(255),
	title_url		VARCHAR(255),
	PRIMARY KEY ( site_type, name ),
) TYPE=MyISAM COMMENT='Site Plugin Link';

The name is the unique identifier for the link, and is not generally
used otherwise.  

The description is what will be displayed as the alternate text for the
image and to the right of the image (or superimposed, if we want to
implement a GD function to superimpose the description over the 
site image defined at the site_plugin table level)

The url is the link to the item itself on the site, with {variables} matching
specific ITEM_ATTRIBUTE.S_ATTRIBUTE_TYPE values stored against the item.  The
process will use the 'url' value if at least one site_type specific 
item_attribute exists for the item.  Its assumed that if one is found, all will
be populated.

A title_url link is provided where no item_attribute's are found for the
url value, and the title_url will be generated using the ITEM.TITLE
instead.  However note, that there may actually be {variables} for other
item_attribututes - such as {year}

An example URL value would be:
	http://www.dvdempire.com/Exec/v4_item.asp?item_id={dvdempr_id}

Both the url and title_url values can use the title mask scripting syntax for
some simple procedural logic.  For instance, we might have a title_url of

http://www.dvdempire.com/exec/v5_search_item.asp?string={title}&site_id={switch(s_item_type, DVD, 4, DVDAUDIO, 12, GAME, 2, BOOK, 42, VHS, 42, DVHS, 42)}&display_pic=1&media_id={switch(s_item_type, BOOK, 16, VHS, 3, DVHS, 24)}

The title_url will only be used if any of the {variables} are not defined for the
url value.  The title_url {variables} will not be checked prior to being used, it
will be used regardless, which may lead to unexpected results.


URL and TITLE_URL mask functions
--------------------------------

For the site_plugin_link url and title_url values, new title_mask
functions will be introduced specifically for site plugins, to access
information from the site_plugin_conf table.

	site_plugin_conf(type, name, value)
	
The type can be KEYID or VALUE

For value or key you can use another {variable} in context of the current
item, such as {s_item_type}

NOTE: All variables included in the url and title_url fields will be
rawurlencoded prior to being included in the final HREF links.

-------------------------------------------------------------------------

Lets have a look at how an existing site plugin (amazon) might be defined using
the new tables.

1)	$site_title, $site_image_icon, $site_external_link are all configured in the
	site_plugin table:

	$site_title 		=> title		VARCHAR(50) NOT NULL,
	$site_image_icon	=> img			VARCHAR(255) NOT NULL,
	$site_external_link	=> external_url	VARCHAR(255) NOT NULL,

2)	$title_attribute = "alt_title";

	INSERT INTO site_plugin_s_attribute_type_map(site_type, variable, s_item_type_group, s_item_type, s_attribute_type)
	VALUES ('amazon', 'title', '*', '*', 'ALT_TITLE');

	INSERT INTO site_plugin_s_attribute_type_map(site_type, variable, s_item_type_group, s_item_type, s_attribute_type)
	VALUES ('amazon', 'title', '*', '*', 'TITLE');

3)	$site_attribute_map = array(
				'DEFAULT'=>array(
					'genre'=>'category',
					'blurb'=>'movie_plot'),
				'BOOK'=>array(
					'blurb'=>'comments'));

	INSERT INTO site_plugin_s_attribute_type_map(site_type, variable, s_item_type_group, s_item_type, s_attribute_type)
	VALUES ('amazon', 'genre', 'VIDEO', '*', 'MOVIEGENRE');

	INSERT INTO site_plugin_s_attribute_type_map(site_type, variable, s_item_type_group, s_item_type, s_attribute_type)
	VALUES ('amazon', 'genre', 'MUSIC', '*', 'MUSICGENRE');
	
	INSERT INTO site_plugin_s_attribute_type_map(site_type, variable, s_item_type_group, s_item_type, s_attribute_type)
	VALUES ('amazon', 'genre', '*', 'BOOK', 'BOOKGENRE');

	INSERT INTO site_plugin_s_attribute_type_map(site_type, variable, s_item_type_group, s_item_type, s_attribute_type)
	VALUES ('amazon', 'genre', '*', 'GAME', 'GAMEGENRE');
	
	INSERT INTO site_plugin_s_attribute_type_map(site_type, variable, s_item_type_group, s_item_type, s_attribute_type)
	VALUES ('amazon', 'blurb', 'VIDEO', '*', 'MOVIE_PLOT');

	INSERT INTO site_plugin_s_attribute_type_map(site_type, variable, s_item_type_group, s_item_type, s_attribute_type)
	VALUES ('amazon', 'blurb', 'MUSIC', '*', 'COMMENTS');

	INSERT INTO site_plugin_s_attribute_type_map(site_type, variable, s_item_type_group, s_item_type, s_attribute_type)
	VALUES ('amazon', 'blurb', '*', 'BOOK', 'COMMENTS');

	NOTE: The 'category' mapping will be changed in the new structure, to the specific s_attribute_type, as the
	item_input process will be looking for the specific s_attribute_type instead of the generic 'category', the
	same for 'title' too as described above.

4)	$site_input_fields = array(
				array(field=>"title", type=>"", value=>"", refresh_mask=>"{title}"),
				array(field=>"amazonasin", type=>"text", value=>"", refresh_mask=>"{amazonasin}"),
				array(field=>"amazonisbn", type=>"hidden", value=>"", refresh_mask=>"{isbn}"));

	AND:
	
	$LANG_VARS['site']['amazon'] = array(
			'input_fields'=>array(
				'title'=>'Title Search',
				'amazonasin'=>'ASIN/ISBN Number',
				'amazonisbn'=>'ISBN (Book)'));

	INSERT INTO site_plugin_input_field (site_type, field, order_no, description, prompt, type, value, refresh_mask)
	VALUES('amazon', 'title', '', 'Title Search', 'text', '', '{title}')

	INSERT INTO site_plugin_input_field (site_type, field, order_no, description, prompt, type, value, refresh_mask)
	VALUES('amazon', 'amazonasin', '', 'ASIN/ISBN Number', 'text', '', '{ifdef(amazonasin,{amazonasin},if(s_item_type==BOOK,{isbn},''))}')

	NOTE: 'text' is default 'type' for the new table.

	NOTE: The amazon plugin no longer needs the amazonisbn value, because the prompt for amazonasin, is either
	the asin or an isbn, so we can try either, and since amazon ISBN for books is exactly the same as ASIN, we
	can do away with the amazonisbn field altogether. The complicated refresh_mask is required so we can support
	BOOK's created with another plugin, but that will refresh quite happily with the amazon one, because the
	ISBN attribute is set.
	
5)	$amazon_item_type_to_index_map = array("CD"=>"music","MP3"=>"music","BOOK"=>"books", "GAME"=>"videogames", 
					"VCD"=>"dvd", "DIVX"=>"dvd", "LD"=>"dvd");

	INSERT INTO site_plugin_conf (site_type, name, description, keyid, value)
	VALUES('amazon', 'item_type_to_index_map', 'Description goes here', 'CD', 'music')

	INSERT INTO site_plugin_conf (site_type, name, description, keyid, value)
	VALUES('amazon', 'item_type_to_index_map', '', 'MP3', 'music')

	INSERT INTO site_plugin_conf (site_type, name, description, keyid, value)
	VALUES('amazon', 'item_type_to_index_map', '', 'BOOK', 'books')

	INSERT INTO site_plugin_conf (site_type, name, description, keyid, value)
	VALUES('amazon', 'item_type_to_index_map', '', 'GAME', 'videogames')

	INSERT INTO site_plugin_conf (site_type, name, description, keyid, value)
	VALUES('amazon', 'item_type_to_index_map', '', 'VCD', 'dvd')

	INSERT INTO site_plugin_conf (site_type, name, description, keyid, value)
	VALUES('amazon', 'item_type_to_index_map', '', 'DIVX', 'dvd')

	INSERT INTO site_plugin_conf (site_type, name, description, keyid, value)
	VALUES('amazon', 'item_type_to_index_map', '', 'LD', 'dvd')

6)	$amazon_index_attribute_map = array('books'=>array('listprice'=>'coverprice'), 
										'dvd'=>array('listprice'=>'ret_price'), 
										'videogames'=>array('listprice'=>'coverprice'),
										'music'=>array('listprice'=>'coverprice'));

	The logic of this variable is to be slightly changed, so that amazon plugin always parses a 'listprice' attribute,
	and then maps it appropriately based on what s_item_type we are dealing with.  The 'item_type_to_index_map'
	configuration from 5) actually maps the s_item_type to the correct amazon index, so we are all ok here!
	
	INSERT INTO site_plugin_s_attribute_type_map(site_type, variable, s_item_type_group, s_item_type, s_attribute_type)
	VALUES ('amazon', 'listprice', 'video', '*', 'RET_PRICE');

	INSERT INTO site_plugin_s_attribute_type_map(site_type, variable, s_item_type_group, s_item_type, s_attribute_type)
	VALUES ('amazon', 'listprice', '*', '*', 'COVERPRICE');

7) $amazon_platform_to_gamesystem_map = array("PlayStation"=>"PS1", "PlayStation2"=>"PS2", "Sega Dreamcast"=>"DREAMCAST",
					"Nintendo 64"=>"N64", "GameCube"=>"GAMECUBE", "Xbox"=>"XBOX",
					"Game Boy Color"=>"GAMEBOY", "Game Boy"=>"GAMEBOY", 
					"Game Boy Advance"=>"GAMEBOYADVANCE", "Mac OS"=>"MACCDROM",
					"Windows"=>"PCCDROM");//special process exists to match all Windows platform combo's as 'Windows'

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMESYSTEM', 'PlayStation', 'PS1')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMESYSTEM', 'PlayStation2', 'PS2')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMESYSTEM', 'Sega Dreamcast', 'DREAMCAST')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMESYSTEM', 'Nintendo 64', 'N64')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMESYSTEM', 'GameCube', 'GAMECUBE')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMESYSTEM', 'Xbox', 'XBOX')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMESYSTEM', 'Game Boy Color', 'GAMEBOY')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMESYSTEM', 'Game Boy', 'GAMEBOY')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMESYSTEM', 'Game Boy Advance', 'GAMEBOYADVANCE')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMESYSTEM', 'Mac OS', 'MACCDROM')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMESYSTEM', 'Windows', 'PCCDROM')

8)	$amazon_rating_to_gamerating_map = array("early_childhood"=>"EC", "teen"=>"T", "everyone"=>"E",
					"mature"=>"M", "adults_only"=>"AO", "rating_pending"=>"RP");

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMERATING', 'early_childhood', 'EC')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMERATING', 'teen', 'T')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMERATING', 'everyone', 'E')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMERATING', 'mature', 'M')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMERATING', 'adults_only', 'AO')

	INSERT INTO site_plugin_s_attribute_type_lookup_map(site_type, s_attribute_type, value, lookup_attribute_val)
	VALUES('amazon', 'GAMERATING', 'rating_pending', 'RP')

9)	$amazon_video_ratio_map = array("1.33", "1.66", "1.78", "1.85", "2.35", "2.78");

This particular configuration item was a quick hack and really needs to be rethought.

Instead what the plugin should do is actually query the s_attribute_type_lookup table for all
relevant ratio lookup values.  It will first of all check for a site_plugin_s_attribute_type_map for
'ratio', and will use that or 'RATIO' to query the s_attribute_type_lookup table.

10)	$amazon_video_audio_lang_map = array("ENGLISH_2.0"=>array("English", "2.0"), 
								"ENGLISH_5.0"=>array("English", "5.0"), 
								"ENGLISH_5.1"=>array("English", "5.1"), 
								"ENGLISH_6.1_EX"=>array("English", "6.1", "EX"), // Dolby Digital 6.1 EX
								"ENGLISH_6.1_DTS_ES"=>array("English", "6.1", "DTS", "ES"), // English (6.1 DTS ES)
								"ENGLISH_6.1"=>array("English", "6.1"),
								"ENGLISH_DTS"=>array("English", "DTS"),
								"ENGLISH_DTS"=>array("English", "DTS"),
								"FRENCH"=>array("French"), 
								"SPANISH"=>array("Spanish"), 
								"GERMAN"=>array("German"));

This one also needs to be rethought - not sure here, but this is a pretty extreme example.  Perhaps we should
find out what values amazon uses and provide a detailed set of site_plugin_s_attribute_type_lookup_map records
for each of the different occurences, that would certainly make more sense.

11)	$amazon_video_subtitle_map = array("English", "French", "Spanish", "German");

See 9) for similiar solution, 

12)	if(is_array($item_r))
	{	
		$amazon_id = fetch_attribute_val($item_r['item_id'], "AMAZONASIN", NULL);		 
		$index_type = ifempty($amazon_item_type_to_index_map[$item_r['s_item_type']], strtolower($item_r['s_item_type']));
		if(strlen($amazon_id)>0)
		{
			$site_item_link_rs[] = array(link=>$LANG_VARS['more_info'],url=>"http://www.amazon.com/exec/obidos/ASIN/$amazon_id");

			// Always generate link, even if no extra images.
			if($index_type == "videogames")
				$site_item_link_rs[] = array(link=>$LANG_VARS['screenshots'], url=>"http://www.amazon.com/exec/obidos/tg/stores/detail/-/videogames/$amazon_id/pictures#more-pictures");
		}
		else
		{
			// Amazon does not appear to handle any '&' in the external-search at all, so replace with 'and' which
			// should suit most things.
			$site_item_link_rs[] = array(link=>$LANG_VARS['more_info'],url=>"http://www.amazon.com/exec/obidos/external-search?tag=&index=$index_type&keyword=".rawurlencode(str_replace("&", "and", $item_r['title'])));
		}
	}

	INSERT INTO site_plugin_link(site_type, s_item_type_group, s_item_type, description, order_no, url, title_url)
	VALUES('amazon', 'NULL', 'NULL', '$LANG_VARS['more_info']', '1', 'http://www.amazon.com/exec/obidos/ASIN/{amazon_id}', 'http://www.amazon.com/exec/obidos/external-search?tag=&index={config_var_value(item_type_to_index_map, KEY, {s_item_type})}&keyword={title}')

	INSERT INTO site_plugin_link(site_type, s_item_type_group, s_item_type, description, order_no, url, title_url)
	VALUES('amazon', 'NULL', 'BOOK', '$LANG_VARS['screenshots']', '1', 'http://www.amazon.com/exec/obidos/tg/stores/detail/-/videogames/{amazon_id}/pictures#more-pictures')

13)	if(!is_array($LANG_VARS['site']) || !is_array($LANG_VARS['site']['amazon']))
	{
		$LANG_VARS['site']['amazon'] = array('description'=>'A good source of CD, DVD (Region 1), VHS, Books, Games, etc.',
								'input_fields'=>array('title'=>'Title Search','amazonasin'=>'ASIN/ISBN Number','amazonisbn'=>'ISBN (Book)'));
	}

This being defined elsewhere and has already described above (at least for the input_fields).  The 'description' field
is described in the site_plugin table.

No definition of site plugin fields will be possible now at the lang/$LANGUAGE.inc.php level.  At a later date a metalayer
for language translations may be provided for all prompts, etc.