function galleryObj(o_anim_fp,s_objname_fp,a_images_fp,s_plimage_fp,s_interfacelangpath_fp) {
    //it is assumed that there is a selector class for #img-gallery and #div-galleryimg by default
    /**** BEGIN PRIVATE VARIABLES ****/
    var a_img = a_images_fp; //array of images (expects [i][0] = path, [i][1] = description)
    var a_lang;
    var a_param = new Array(); //array of default parameters for all actions
    var a_preloads = new Array(); //array of image objects for preloading
    var i_img_index; //current index within a_img
    var i_preloads = 0; //image preload tracking
    //note: o_anim is external because of the timeout() callbacks in animObj()
    var o_anim = o_anim_fp; //js animation object
    var s_langpath;
    var s_plimage; //path to preloader image
    var s_objname = s_objname_fp; //object name callback

    //"CONSTANTS"
    //a_param default values
    //common
    var DEF_IMGDIV = 'div-galleryimg'; //id of gallery div
    var DEF_IMGID = 'img-gallery'; //id of targeted image
    var DEF_IMGWIDTH = 593; //default image width
    var DEF_IMGHEIGHT = 394; //default image height
    var DEF_CAPTDIV = 'div-imgcaption'; //id of the div containing caption text
    var DEF_CTRLDIV = new Array('div-larrow','div-rarrow'); //names of the divs with control arrows
    //imgchange
    var DEF_IMGCHG_MSEC = 25; //milliseconds
    var DEF_IMGCHG_FADE1 = -10; //fade rate 1
    var DEF_IMGCHG_FADE2 = 10; //fade rate 2
    var DEF_IMGCHG_STARTOPA1 = 100; //start opacity 1
    var DEF_IMGCHG_STARTOPA2 = 0; //start opacity 2
    //event handler refs
    var HND_LOAD = 'load';
    var HND_LOADIE = 'onload';
    var HND_ERR = 'error';
    var HND_ERRIE = 'onerror';
    var HTML_REFERLINK = '<a href="mailto:?subject=_subj_&body=_body_">_link_</a>';
    //a_param indices
    var KEY_COMMON = 'common';
    var KEY_IMGCHNG = 'imgchange';
    var KEY_IMGDIV = 'imgdiv';
    var KEY_IMGID = 'imgid';
    var KEY_CAPDIV = 'captiondiv';
    var KEY_CTRLDIV = 'ctrldiv';
    var KEY_MSEC = 'mseconds';
    var KEY_FADE1 = 'faderate1';
    var KEY_FADE2 = 'faderate2';
    var KEY_STARTOPA1 = 'startopacity1';
    var KEY_STARTOPA2 = 'startopacity2';
    //misc array indices
    var KEY_FILENAME = 'imgpath'; //a_img[i][0] alias (filename)
    var KEY_DESC = 'description'; //a_img[i][1] alias (desc)
    var KEY_LBLSENDREF = 'label-sendfriend';
    var KEY_REFEMAILSUBJ = 'email-sendfriendsubj';
    var KEY_REFEMAILBODY = 'email-sendfriendbody';
    var KEY_PRODUCT = 'products';
    var KEY_DESCFRIENDEMAIL = 'desc-friendaddress';
    //HTML strings
    var HTML_IMGTAG = '<img id="_imgid_" src="_imgsrc_" />';
    //replacement keys for HTML_ strings
    var RGX_SUBJ = /_subj_/;
    var RGX_BODY = /_body_/;
    var RGX_LINK = /_link_/;
    var RGX_IMGSRC = /_imgsrc_/;
    var RGX_IMGID = /_imgid_/;
    var RGX_EMAIL = /_email_/;
    //misc
    var PLINTERVAL = 500; //preload delay interval
    var VISBLOCK = 'block';
    var VISNONE = 'none';
    var IEAPPNAME = 'Microsoft Internet Explorer';
    /**** END PRIVATE VARIABLES ****/


    /**** BEGIN PUBLIC METHOD POINTERS ****/
    this.doFadeChange = doFadeChange;
    this.setParam = setParam;
    this.doImgPreload = doImgPreload;
    this.setImgPreload = setImgPreload;
    /**** END PUBLIC METHOD POINTERS ****/


    /**** BEGIN "CONSTRUCTOR" ACTIONS ****/
    //prime the sub arrays in a_param
    a_param[KEY_COMMON] = new Array();
    a_param[KEY_IMGCHNG] = new Array();
    getLang(s_interfacelangpath_fp);
    setParam('',null);  //set a_param with default values
    setPreloadImg(s_plimage_fp); //set the PRELOAD image path
    /**** END "CONSTRUCTOR" ACTIONS ****/


    /**** BEGIN PUBLIC METHODS ****/
    function doFadeChange(i_direction_fp) {
        //browse through a looping gallery with fade transition
        //i_direction_fp will also be interpreted as the increment of movement in index
        if (i_direction_fp > 0) {
            if (i_img_index >= (a_img.length - 1)) {
                i_img_index = 0;
            } else {
                i_img_index = i_img_index + i_direction_fp;
            }
        } else {
            if (i_img_index <= 0) {
                i_img_index = (a_img.length - 1);
            } else {
                i_img_index = i_img_index + i_direction_fp;
            }
        }
        o_anim.setImgFadeSwap(a_param[KEY_COMMON][KEY_IMGID],a_img[i_img_index][KEY_FILENAME],a_param[KEY_IMGCHNG][KEY_MSEC],a_param[KEY_IMGCHNG][KEY_FADE1],a_param[KEY_IMGCHNG][KEY_FADE2],a_param[KEY_IMGCHNG][KEY_STARTOPA1],a_param[KEY_IMGCHNG][KEY_STARTOPA2]);
        o_anim.doImgFadeSwap();
        setCaptionDiv(a_img[i_img_index][KEY_DESC]);
    }

    function doImgPreload() {
        //preload images; disables gallery controls while images are loaded
        doStartPreload();
    }
    
    function setImgPreload(i_index_fp) {
        //set the src of preloading image
        //this is public to accomodate timeout call from doImgLoad
        a_preloads[i_index_fp].src = a_img[i_index_fp][KEY_FILENAME];
    }
    
    function setParam(s_set_fp,a_newparam_fp) {
        //when passing new variables, they have to come in a name-indexed array as shown in each grouping below
        switch (s_set_fp) {
            case 'common':
            a_param[KEY_COMMON][KEY_IMGDIV] = a_newparam_fp[KEY_IMGDIV];
            a_param[KEY_COMMON][KEY_IMGID] = a_newparam_fp[KEY_IMGID];
            a_param[KEY_COMMON][[KEY_CAPDIV]] = a_newparam_fp[[KEY_CAPDIV]];
            a_param[KEY_COMMON][KEY_CTRLDIV] = a_newparam_fp[KEY_CTRLDIV];
            case 'imgchange':
            a_param[KEY_IMGCHNG][KEY_MSEC] = a_newparam_fp[KEY_MSEC];
            a_param[KEY_IMGCHNG][KEY_FADE1] = a_newparam_fp[KEY_FADE1];
            a_param[KEY_IMGCHNG][KEY_FADE2] = a_newparam_fp[KEY_FADE2];
            a_param[KEY_IMGCHNG][KEY_STARTOPA1] = a_newparam_fp[KEY_STARTOPA1];
            a_param[KEY_IMGCHNG][KEY_STARTOPA2] = a_newparam_fp[KEY_STARTOPA2];
            break;
            default:
            a_param[KEY_COMMON][KEY_IMGDIV] = DEF_IMGDIV;
            a_param[KEY_COMMON][KEY_IMGID] = DEF_IMGID;
            a_param[KEY_COMMON][[KEY_CAPDIV]] = DEF_CAPTDIV;
            a_param[KEY_COMMON][KEY_CTRLDIV] = DEF_CTRLDIV;
            a_param[KEY_IMGCHNG][KEY_MSEC] = DEF_IMGCHG_MSEC;
            a_param[KEY_IMGCHNG][KEY_FADE1] = DEF_IMGCHG_FADE1;
            a_param[KEY_IMGCHNG][KEY_FADE2] = DEF_IMGCHG_FADE2;
            a_param[KEY_IMGCHNG][KEY_STARTOPA1] = DEF_IMGCHG_STARTOPA1;
            a_param[KEY_IMGCHNG][KEY_STARTOPA2] = DEF_IMGCHG_STARTOPA2;
            break;
        }
    }
    /**** END PUBLIC METHODS ****/


    /**** BEGIN PRIVATE METHODS ****/
     function doControlVis(b_state_fp) {
        //set the display style of the control layers (grouped in an array)
        var i_index;
        for (i_index in a_param[KEY_COMMON][KEY_CTRLDIV]) {
		if( document.getElementById( a_param[KEY_COMMON][KEY_CTRLDIV][i_index] ) ){
            		document.getElementById(a_param[KEY_COMMON][KEY_CTRLDIV][i_index]).style.display = b_state_fp;
		}
        }
    }
    
    function doFinishPreload() {
        //turn the controls back on and swap the loading message for the first gallery image
        doControlVis(VISBLOCK);
        doShowGallery();
    }
    
    function doImgLoad() {
        //preload the images
        var i_index;
        var o_image;
        var o_timer;
        for (i_index in a_img) {
            o_image = new Image();
            //treat the onerror the same as onload and let the eyes do the debugging
            if (navigator.appName == IEAPPNAME) {
                o_image.attachEvent(HND_LOADIE,setLoadTracker);
                o_image.attachEvent(HND_ERRIE,setLoadTracker);
            } else {
                o_image.addEventListener(HND_LOAD,setLoadTracker,false);
                o_image.addEventListener(HND_ERR,setLoadTracker,false);

            }
            a_preloads.push(o_image);
            //wait a moment between loads to give ie6 a chance to breathe
            o_timer = setTimeout(s_objname + ".setImgPreload('" + i_index + "')", PLINTERVAL);
        }
    }

    function doShowGallery() {
    	var o_util = new siteUtils('o_util');
    	if (o_util.getUriValue('id')) {  //this little hack lets you specify the image to start on by sending an id param in the GET
    		i_img_index = new Number(o_util.getUriValue('id'));
    	} else {
    		i_img_index = 0;
    	}
        setImgDiv(outImgHTML(a_param[KEY_COMMON][KEY_IMGID],a_img[i_img_index][KEY_FILENAME]));
        setCaptionDiv(a_img[i_img_index][KEY_DESC]);
    }
    
    function doShowPreloader() {
        setImgDiv(outImgHTML(a_param[KEY_COMMON][KEY_IMGID],s_plimage));
        setCaptionDiv('');
    }

    function doStartPreload() {
        //get things rolling by hiding any controls, setting the loading image, and starting the preloads
        doControlVis(VISNONE);
        doShowPreloader();
        doImgLoad();
    }
    
    function getLang(s_interfacelangpath_fp) {
        if (s_interfacelangpath_fp != '') {
            //var o_ajaxreq1 = new ajaxReq('o_ajaxreq1');
            //o_ajaxreq1.doServerRequest(s_interfacelangpath_fp,'',setInterfaceLang);
		setInterfaceLang();
        }
    }
    
    function outImgHTML(s_id_fp,s_src_fp) {
        var s_html = HTML_IMGTAG;
        s_html = s_html.replace(RGX_IMGID,s_id_fp);
        s_html = s_html.replace(RGX_IMGSRC,s_src_fp);
        return s_html;
    }
    
    function setCaptionDiv(s_html_fp) {
    	if (s_html_fp != '') { //hack to make the send to a friend link (oh SO ugly!!!)
    		var o_util = new siteUtils('o_util');
    		var s_category = o_util.getUriValue('category');
    		var s_season = o_util.getUriValue('season');
    		var s_referlink = escape('http://www.bfcink.com/index.php?section=bfcproductgallery&category=' + s_category + '&season=' + s_season + '&id=' + i_img_index  + '&uriLang=' + country);
    		var s_friendlink = HTML_REFERLINK;
    		s_friendlink = s_friendlink.replace(RGX_BODY, (a_lang[KEY_PRODUCT][KEY_REFEMAILBODY] + s_referlink));
    		s_friendlink = s_friendlink.replace(RGX_SUBJ, a_lang[KEY_PRODUCT][KEY_REFEMAILSUBJ]);
    		s_friendlink = s_friendlink.replace(RGX_LINK, a_lang[KEY_PRODUCT][KEY_LBLSENDREF]);
    		s_html_fp  += '<br/>' + s_friendlink;
    	}     		
		if(  document.getElementById(a_param[KEY_COMMON][[KEY_CAPDIV]]) ){
        		document.getElementById(a_param[KEY_COMMON][[KEY_CAPDIV]]).innerHTML = s_html_fp;    	
    		}
	}
    
    function setImgDiv(s_html_fp) {
	if( document.getElementById(a_param[KEY_COMMON][KEY_IMGDIV]) ){
        	document.getElementById(a_param[KEY_COMMON][KEY_IMGDIV]).innerHTML = s_html_fp;
	}
    }

    function setInterfaceLang(a_result_fp) {
	a_lang = bfcinkHash["language"];
    	//a_lang = a_result_fp;
    }
    
    function setLoadTracker() {
        //track each preload as it completed and go to cleanup when done
        if (i_preloads == 0) {  //show the preloader if we're just getting started
            doShowPreloader();
        }
        i_preloads++;
        if (i_preloads == a_img.length) { //if we've done as many preloads as there are image in the array, we're done!
            doFinishPreload();
        }
    }

    function setPreloadImg(s_plimage_fp) {
        //set the preload img's path
        //this is the image we see while the preload is happening to let guest know to wait
        s_plimage = s_plimage_fp;
    }
    /**** END PRIVATE METHODS ****/
}
