/*******************************************
SINGLE_ELEMENT
    For elements that contain single primative values (e.g. date_founded)
 */
var map_id=1;
function replaceAll(text, strA, strB) {
    return text.replace(new RegExp(strA,"g"), strB);
}
 function hide(id){
            $(id).hide();
        }
function singleElement(idName,options) {

    var topicName = options.topicName;
    var currentVal = options.currentVal;
    var property = options.property;
    var propertyType = options.propertyType;
    var postCommand = '/company_info/write/';
    var useSuggest = options.useSuggest;

    var htmlName = idName;
    
    var formElement = $('#'+htmlName)
        .html((currentVal ? currentVal : "") + " <em>[Edit]</em>")
        .attr("name", "e_value=" + (currentVal ? currentVal : "") + " pid="+property)
        .click(
            function(e) {
            if ($(this).length > 0) {
            var id = $(this).get(0).id;
            id = id.replace(/span_/, "");
            if ($('#'+id).length == 0) {
                var text = $(
                    '<form id="form_' + id + '" name="form_' +id+'"><input type="text" name="'+
                    $("#span_"+id).attr('name')+'" id="'+id+'" />' +
                    '<input type="hidden" name="tid" value="/en/'+topicName+'" id="tid_'+id+'"/>' +
                    '<input type="hidden" name="orig_val" value="'+currentVal+'" id="originalVal"/>' +
                    '<input type="hidden" name="property" value="/en/'+topicName+'" id="tid_'+id+'"/>' +
                    '<input type="hidden" name="id_value" value="'+id+'" id="id_val"/>' +
                    '<input type="submit" id="submit_'+id+'" value="Save" /> <input type="button" id="cancel_'+id+'" value="Cancel" /></form>');
                    
                    $(this).parent().append(text);
                    
                    var options = {
                        soft: true,
                        ac_param: {
                            type: propertyType
                            }
                        };
                    if(useSuggest){
                        $('#'+id).freebaseSuggest(options);
                    }
                    $('#'+id).val($(this).html().substring(0, $(this).html().indexOf(' <em>[Edit]</em>')))
                    
                    // SUBMIT the edit:
                    $('#submit_'+id).bind('click',
                        function (e,data) {
                        if ($(this).length > 0) {
                            var id = $(this).get(0).id;
                                id = id.replace(/submit_/, "");
                                $('#span_'+id)
                                .attr("name", "e_value=" + $('#'+id).val() + " pid="+property)
                                .html($('#'+id).val() + " <em>[Edit]</em>")
                                .toggle();
                                $('#form_'+id).toggle();
                                // Disable all of the Tabs, forcing the user to use the SYNC button
                                $("#tabbed-container").tabs({ disabled: [0, 1, 2, 3, 4] });
                                var objects = new Object();
                                for (var i = 0; i < $("#form_"+id + " > input").length; i++) {
                                    var o = $("#form_"+id + " > input").get(i).id;
                                    if ($('#'+o).attr('name') != 'undefined' || typeof($('#'+o).attr('name')) != 'undefined') {
                                        if ($('#'+o).attr('type') && $('#'+o).attr('type').toLowerCase() != 'button' && $('#'+o).attr('type').toLowerCase() != 'submit') {
                                            var s = $('#'+o).attr('name');
                                            s = s.split(" ");
                                            for (var x in s) {
                                                if (s[x] && typeof (s[x].split) != 'undefined') {
                                                    var str = s[x].split("=");
                                                    if (str.length == 2) {
                                                        objects[str[0]] = str[1];
                                                    }
                                                }
                                            }
                                            objects[o] = $('#'+o).attr('value');
                                        }
                                    }
                                }
                                
                                $.ajax({
                                    type: "POST",
                                    url: postCommand+topicName +'/',
                                    data: objects,
                                    success: function(m) {
                                        //if (console && console.log) {
                                        //  console.log(m);
                                            perform_touch(freebase_domain);
                                        //}
                                    },
                                    error: function(m) {
                                    },
                                    dataType: "text",
                                    cache: false
                                }); 
                                return false;
                            }
                        }
                    );
                $('#cancel_'+id).bind('click',
                    function (e,data) {
                        if ($(this).length > 0) {
                            var id = $(this).get(0).id;
                            id = id.replace(/cancel_/, "");
                            $('#'+id).val($("#span_"+id).html().substring(0, $("#span_"+id).html().indexOf(' <em>[Edit]</em>')))
                            $('#span_'+id).toggle();
                            $('#form_'+id).toggle();
                            return false;
                        }
                    }
                );
            } else {
                $("#form_"+id).toggle();
            }
            $('#'+id).focus();
            
            $(this).toggle();   
        }
        }
        )
        
}

/*******************************************
BLURB_ELEMENT
    For elements that edit the topic overview blurb 
 */
function blurbElement(idName, options){

    var postCommand = '/topic_info/write_blurb/';

    var topicName = options.topicName;
    var currentVal = options.currentVal;
    var property = options.property;
    var propertyType = options.propertyType;
    var topicID = options.topic_id;
    var articleID = options.article_id;
    var pID = options.p_id;
    var domain_used = options.domain_used;
    var topic_domain = options.topic_domain;
    var topic_id = options.topic_id;
    var num_chars = options.num_chars;
    
        
    var htmlName = idName;
    
    var display_id = 'display_'+htmlName;
    var current_val_html = '<div id="'+display_id+'">' + (currentVal ? currentVal : '') + ' <em>[Edit]</em></div>';
    var formElement = $('#'+htmlName)
    $('#'+htmlName).html(current_val_html); 
    $('#'+display_id)   
        .attr("name", "e_value=" + (currentVal ? currentVal : "") + " pid="+property)   
        .click(
            function(e) {
            if ($(this).length > 0) {
                                
            var id = $(this).get(0).id;
            var parent_id = id.replace(/display_/, "");
            var current_blurb = $(this).html().substring(0, $(this).html().indexOf(' <em>[Edit]</em>'));
            
            // Remove the display elements:
            $('#'+parent_id).empty();
            
            //if ($('#'+id).length == 0) {
            var edit_id ='edit_' +parent_id;
                var text = $(
                    '<form id=form_"'+parent_id+'"><textarea type="textarea" "style="width: 600px; min-height: 100px; class="expanding" name="'+
                    $("#"+edit_id).attr('name')+'" id="'+id+'">' + current_blurb +'</textarea>'+
                    '<input type="hidden" name="pid" value="'+property+'" id="pid"/>'+
                    //'<input type="hidden" name="e_value" value="'+(currentVal ? currentVal : "")+'" id="e_value"/>'+
                    '<input type="hidden" name="tid" value="/en/'+topicName+'" id="tid_'+id+'"/>' +
                    '<input type="hidden" name="orig_val" value="'+currentVal+'" id="originalVal"/>' +
                    '<input type="hidden" name="property" value="/en/'+topicName+'" id="tid_'+id+'"/>' +
                    '<input type="hidden" name="id_value" value="'+id+'" id="id_val"/>' +
                    '<br></br><input type="submit" id="submit_'+parent_id+'" value="Save" /> <input type="button" id="cancel_'+parent_id+'" value="Cancel" /></textarea>');
                    
                $('#'+parent_id).append(text);
                $('#'+edit_id).val(current_blurb);
                //; 
                /*
                var options = {
                    soft: true,
                    ac_param: {
                        type: propertyType
                        }
                    };
                */
                //$('#'+id).
                
                    $('#submit_'+parent_id).bind('click',
                        function (e,data) {
                        if ($(this).length > 0) {
                            // Create the button for syncing the reads with the written content:
                            $("#tabbed-container").tabs({ disabled: [0, 1, 2, 3, 4] });
                            createSyncButton(topicName);
                            
                            var id = $(this).get(0).id;
                                id = id.replace(/submit_/, "");
                                
                                var objects = new Object();
                                //objects["pid"] = property;
                                objects["e_value"] = $('#display_'+id).val();
                                objects["article_id"] = articleID;
                                objects["topic_id"] = topicID;
                                objects["p_id"] = pID;
                                
                                /*
                                $('#'+id)
                                .attr("name", "e_value=" + $('#'+id).val() + " pid="+property)
                                .html($('#'+id).val() + " <em>[Edit]</em>")
                                .toggle();
                                
                                $('#form_'+id)
                                .attr("name", "e_value=" + $('#'+id).val() + " pid="+property);
                                
                                $('#form_'+id).toggle();
                                var objects = new Object();
                                //objects["pid"] = property;
                                objects["e_value"] = $('#'+id).val();
                                objects["article_id"] = articleID;
                                objects["topic_id"] = topicID;
                                objects["p_id"] = pID;
                                
                                for (var i = 0; i < $("#form_"+id + " > input").length; i++) {
                                    var o = $("#form_"+id + " > input").get(i).id;
                                    if ($('#'+o).attr('name') != 'undefined' || typeof($('#'+o).attr('name')) != 'undefined') {
                                        if ($('#'+o).attr('type') && $('#'+o).attr('type').toLowerCase() != 'button' && $('#'+o).attr('type').toLowerCase() != 'submit') {
                                            var s = $('#'+o).attr('name');
                                            s = s.split(" ");
                                            for (var x in s) {
                                                if (s[x] && typeof (s[x].split) != 'undefined') {
                                                    var str = s[x].split("=");
                                                    if (str.length == 2) {
                                                        objects[str[0]] = str[1];
                                                    }
                                                }
                                            }
                                            objects[o] = $('#'+o).attr('value');
                                        }
                                    }
                                }
                                */
                                // remove the edit fields
                                $('#'+id).empty()
                        
                                // submit the data
                                $.ajax({
                                    type: "POST",
                                    async: false,
                                    url: postCommand+topicName +'/',
                                    data: objects,
                                    success: function(m) {
                                        /*if (console && console.log) {
                                            console.log(m);
                                        }*/
                                    },
                                    error: function(m) {
                                        var test = 0;
                                        test = 0;
                                    },
                                    dataType: "text",
                                    cache: false
                                });
                                // Re-create the blurb element
                                perform_touch(domain_used); 
                                createBlurbElement(domain_used, topicName, topic_domain, topic_id, num_chars, idName);
                                    
                                return false;
                            }
                        }
                    );
                    $('#cancel_'+parent_id).bind('click',
                    function (e,data) {
                        if ($(this).length > 0) {
                            var id = $(this).get(0).id;
                            id = id.replace(/cancel_/, "");
                            //$('#'+id).val($("#edit_"+id).html().substring(0, $("#edit_"+id).html().indexOf(' <em>[Edit]</em>')))
                            //$('#edit_'+id).toggle();
                            //$('#form_'+id).toggle();
                            
                            // remove the edit fields
                            $('#'+id).empty()
                            // Re-create the blurbElement
                            blurbElement(idName, options);                          
                            return false;
                        }
                    }
                );
            //} else {
                //$("#form_"+id).toggle();
            //}
            $('#'+id).focus();
            $(this).toggle();
            return false;   
        }
    }
);
}

function createBlurbElement(domain_used, name, topic_domain, topic_id, num_chars, html_id ){
    // Overview text
    
    var overview_options = {
        topicName: name,
        currentVal: "",
        topic_id: topic_id,
        article_id: "n/a",
        p_id: '/topic/overview',
        domain_used: domain_used,
        topic_domain: topic_domain,
        topic_id: topic_id,
        num_chars: num_chars
    };      
    
    jsonp_totalblurb_freebase(domain_used, name, topic_domain, 500,
        function(m){
        },
        function(m){

            overview_options.currentVal = m.result.body;
            overview_options.article_id = m.article_id; 
            /*          
            overview_options = {
                currentVal: m.result.body,
                article_id: m.article_id
            };      
            */ 
            blurbElement(html_id, overview_options);
        },
        function(m){
            var test = 0;
        }
    );
    
    blurbElement(html_id, overview_options);
    

}

/*******************************************
MULTI_ELEMENT
    For elements that contain an array of elements of the same type 
         (e.g. the medical_focus property found in company:
            Amgen -> Cancer, Anemia, Cardiovascular disease, etc)
*********************************************/

/** 
 * Creates form edit element for single-typed array values.
 * @param idName                     
 * @param options   .topicName      - the name of the given topic
 *                  .currentVals    - the current list of array values
 *                  .property       - the property of the given topic that links out to the array values
 *                  .type           - the given topic's type
 *                  .propertyType2  - the property's type that will be used for the search suggest
 *                  .propertyTypeCreate - the property's type(s) that will be used for creating new topics
 */
function multiElement(idName, options, domain_used) {
    
    var topicName = options.topic_name;
    var currentVals = options.current_vals;
    var property = options.property;
    var topic_type = options.type;      
    var propertyType = options.property_type;
    var postCommand = '/topic_info/write_multi/';

    var html_id = idName;   
    var display_id = 'display_'+html_id;            
    var currentValHtml = '<div id="'+display_id+'">';
    
    for(var i=0;i<currentVals.length; i++){
        currentValHtml += currentVals[i].name;
        currentValHtml += (i<currentVals.length -1 ? '; ' : '');
    }
    currentValHtml += "<em>[Edit]</em></div>"
    arrLength = currentVals.length;


    var addArray = [];
    var addArray2 = [];
    $('#'+html_id).html(currentValHtml);
    $('#'+display_id)   
        .click(
            function(e) {
            
                if ($(this).length > 0) {
                    
                    var id = html_id;//$(this).get(0).id;
                    
                    var parentElement = $('#'+html_id);
                    
                    // remove the display elements
                    parentElement.empty();
                    var textTemp = generateArrayEdit(id, topicName, currentVals, property, propertyType, parentElement);
                    
                    //var id_read = $(id2);
                    
                    $('#'+id).val($(this).html().substring(0, $(this).html().indexOf(' <em>[Edit]</em>')))
                                        
                    $('#add_'+id).bind('click',
                        function (e,data){
                            if ($(this).length > 0) {
                                var id = $(this).get(0).id;
                                var id_full = id.replace(/add_/,'');
                                onAddMulti(id_full, propertyType);
                                        
                            }
                        }
                    );
                    $('#submit_'+id).bind('click',
                        function (e,data){
                            if ($(this).length > 0) {
                                var id = $(this).get(0).id;
                                $("#tabbed-container").tabs({ disabled: [0, 1, 2, 3, 4] });
                                onSubmitMulti(id,options, domain_used);
                                 // Create the button for syncing the reads with the written content:
                                createSyncButton(topicName);
                                
                            }
                        return false;
                        }
                    );
                    
                    $('#cancel_'+id).bind('click',
                        function (e,data){ 
                            if ($(this).length > 0) {
                                var id = $(this).get(0).id;
                                onCancelMulti(id, options);
                            }
                        }
                    );                  
                    $('#'+id).focus();
                }               
            }
    );              
}


function onSubmitMulti(id,options, domain_used){
    // Looks for new values and the posts them
    var topicName = options.topic_name;
    var currentVals = options.current_vals;
    var property = options.property;
    var topic_type = options.topic_type;
    var propertyType = options.property_type;
    var origVal_ids = options.element_id;
    var currentValsNew = Array();
    var topic_id = options.topic_id;
    var vals_id_prefix = options.vals_id_prefix;
    
    var postCommand = '/topic_info/write_multi/';
    var full_id = id.replace(/submit_/,"");
    
    // TODO this may cause a bug
    var siblings = null;
    if(typeof(vals_id_prefix) != 'undefined'){
        var siblings = $('#'+vals_id_prefix+full_id).children();
    } else {
        var siblings = $('#'+id).siblings();
    }
    
    var newVals = [];
    var newIDs = [];
    var newTopicBools = [];
    var newValIndex = 0;
    for (var i=0;i<siblings.length;i++) {
        var sib = siblings[i];
        if(sib.type=='text' && sib.value.length > 0){
            newVals.push(sib.value);
            newIDs.push(sib.attributes['guid'].value);
            newTopicBools.push(sib.attributes['create_new'].value);
            newValIndex++; 
        }
    }
        
    // First see which values have been added new.
    var vals_to_add = Object();
    vals_to_add['data'] = Array();
    var currents_found = Array();
    for(var a=0; a<currentVals.length;a++){
        currents_found[a] = false;
    }
    for(var i=0;i<newVals.length;i++){
        var newVal = newVals[i];
        var isfound = false;
        for(var j=0;j<currentVals.length;j++){
            if(newVal==currentVals[j].name){
                isfound = true;
                currents_found[j] = true;
            }
        }
        // if the value was not found, it is a new value
        if(!isfound){
            var add_index = vals_to_add['data'].length;
            vals_to_add['data'][add_index]= Object();
            vals_to_add['data'][add_index]['val']=newVal;
            vals_to_add['data'][add_index]['id']=newIDs[i];
            vals_to_add['data'][add_index]['create_new']=newTopicBools[i];                          
        }
    }
    
    // Second, see which values have been removed:
    var vals_to_remove = Object();
    vals_to_remove['data'] = Array();
    for(var i=0;i<currents_found.length; i++){
        if(!currents_found[i]){
            var remove_index = vals_to_remove['data'].length;
            vals_to_remove['data'][remove_index]= Object();             
            vals_to_remove['data'][remove_index]['val']=currentVals[i].name;
            vals_to_remove['data'][remove_index]['id']=currentVals[i].guid;
        }
    }
            
    var propertyTypeCreateString = '['
    for(var a=0;a<propertyType.length;a++){
        propertyTypeCreateString += '"'+propertyType[a]+'"';
        propertyTypeCreateString += (a < propertyType.length - 1? ',' : '');
    }
    propertyTypeCreateString += ']';    

    var newValsStringHTML = newVals.join(';');
                
    // Create json strings that can be sent via HTTP POST
    var vals_to_add_string = JSON.stringify(vals_to_add);
    var vals_to_remove_string = JSON.stringify(vals_to_remove);
    
    var topic1 = new Object();
    topic1['id'] = topic_id;
    topic1['property'] = property;
    
    var topic2 = new Object();
    topic2['type'] = propertyType;
    topic2['type_for_create'] = propertyTypeCreateString;
    topic2['topics_to_add'] = vals_to_add;
    topic2['topics_to_remove'] = vals_to_remove;    
    var objects = new Object();
    objects["topic1"] = JSON.stringify(topic1);
    objects["topic2"] = JSON.stringify(topic2);
    
    // Replace the display form:    
    // remove the edit fields
    $('#'+full_id).empty()
    
    // Write the data to freebase   
    perform_touch(domain_used); 
    $.ajax({
        type: "POST",
        //url: postCommand + topic_id+ '/',
        url: postCommand+'write_multi/',
        data: objects,
        async:   false,
        success: function(m) {
            /*if (console && console.log) {
                console.log(m);
            }*/
        },
        error: function(m) {
        },
        dataType: "text",
        cache: false
    }); 
    
    // Re-obtain the current vals from freebase and re-create the multiElement
    perform_touch(domain_used); 
    perform_freebase_read(
        options.url_read,
        options.current_vals_q,
        function (msg) {
            
            var new_vals = msg.result && msg.result[0] ? msg.result[0] : null;
            
            var new_options = options;
            // Re-create the multiElement with the new values
            new_options.current_vals = new_vals[options.property];
            multiElement(full_id,new_options, domain_used);
        },
        function(m){}
    );

    return false; 
}

// Generates the mutli-element Array for editing:
function generateArrayEdit(id, topicName, currentVals, property, propertyType, parentElement){
    var textTemp = '<form id="form_' + id + '" name="form_' +id+'" >';
    textTemp += multiArrayRowHTML(currentVals, id); 
    textTemp += '<input type="hidden" name="pid" value="'+property+'" id="pid_'+id+'"></input>';
    textTemp += '<input type="hidden" name="property" value="/en/'+topicName+'" id="tid_'+id+'"></input>';
    textTemp += '<input type="hidden" name="array_length" value="'+currentVals.length+'" id="len_orig"></input>';
    textTemp += '<input type="hidden" name="id_value" value="'+id+'" id="id_val"></input>';
    textTemp += '<input type="button" id="add_'+id+'" value="+"></input>'+  
    '<input type="submit" id="submit_'+id+'" value="Save"></input>'+
    '<input type="button" id="cancel_'+id+'" value="Cancel"></input></form>';
    parentElement.append($(textTemp));
    
    fbSuggestMultiRow(id,currentVals,propertyType);
    
    // Add an other element for the user to add values:
    onAddMulti(id, propertyType);
}

/* 
    Returns the html of a single row
*/
function multiArrayRowHTML(currentVals, id){
    var s = '';
    for (var i=0;i<currentVals.length;i++){
        var id_full = id + '_' + i;
        s +=    '<div  id="tooltip'+id_full+'" class="balloon" onclick="hide(this)"  >Either select a choice,<br /> or click<br /> <div style="" class="fbs-selectnew fbs-selectnew-selected">Create new topic</div></div><input type="text" name="'+id_full+'" value="'+currentVals[i].name+'" id="'+id_full+'"'+
                'guid="'+currentVals[i].id+'"" create_new="false"></input>';
    }
    return s;
}
    

// Adds an element to the multi array
function onAddMulti(id,propertyType){
    if($(this).length > 0) {
        
        var currentValsNew = Array();
        var siblings = $('#form_'+id).children();
        
        //id = id.replace(/add_/,"");
        
        var newID = id + '_'+(siblings.length - 7);
        
        // Copy the last column and add entry field.
        var anotherTest = jQuery('<div  id="tooltip'+newID+'" class="balloon" onclick="hide(this)"  >Either select a choice,<br /> or click<br /> <div style="" class="fbs-selectnew fbs-selectnew-selected">Create new topic</div></div><input type="text" name="'+newID+'" value="" id="'+newID+'" create_new="false" style="float:inherit" data_val=""></input> '); 
        
        var entry = $(siblings[siblings.length-4]);
        
        entry.after(anotherTest);
        fbSuggestMulti(newID, propertyType, 'Create new topic');
        
    }
}

// Is the mtapp version of onAddMulti:  
//      Todo: figure out how to make this and onAddMulti a single function
function mt_onAddMulti(id,propertyType){
    //if($(this).length > 0) {
        
        var currentValsNew = Array();
        var siblings = $('#vals_'+id).children();
        //id = id.replace(/add_/,"");
        
        var newID = id + '_'+(siblings.length);
        
        // Copy the last column and add entry field.
        var new_entry = jQuery('<input type="text" name="'+newID+'" value="" id="'+newID+'" create_new="false"></input>'); 
        if(siblings.length > 0){
            var entry = $(siblings[siblings.length-1]);
            entry.after(new_entry);
        } else {
            new_entry.appendTo($('#vals_'+id))
        }
        
        fbSuggestMulti(newID, propertyType, 'Create new topic');
    //}
}

function onCancelMulti(cancel_id, options) {
    if ($(this).length > 0) {
        var id = cancel_id.replace(/cancel_/,"");
        // remove the edit fields
        $('#'+id).empty()
        // Re-create the multiElement
        multiElement(id,options);
        return false;
    }               
}

/*******************************************
COMPOUND_ELEMENT
    For elements that contain an array of compound properties
     (e.g. investment_round property of company topics)
*/
function compoundElement(idName, options, domain_used,flag) {
    
    var topicName = options.topicName;
    var name=topicName;
    name=replaceAll(name, ' ', '-');
    name= name.replace(' ', '-');
    name = name.replace('.', '');
    name = name.replace(',', '');
    name = name.replace('&amp;', '');
    name = name.replace("'", '');

    var topicType = options.topic_type;
    var current_vals = options.current_vals;
    var propertyNames = options.propertyNames;
    var propertyTypes = options.propertyTypes;
    var type = options.type;
    var postCommand = '/topic_info/write_multi/';
    var parent_topic_id = options.topic_id;
    
    var compoundPropertyType = options.compoundPropertyType;
    var compoundProperty = options.compoundProperty;
    var useSuggest = options.useSuggest;

    var html_id = idName;
    var display_id = 'display_'+html_id; 
    var currentValHtml = '<div id="'+display_id+'">' 
    currentValHtml += createStringFromJSON_compound(current_vals, propertyNames);   
    currentValHtml += "<em>[Edit]</em></div>"
    
    var valsArray = Object();
    valsArray.names = Array();
    valsArray.ids = Array();
    $('#'+html_id).html((currentValHtml ? currentValHtml : "") + " <em>[Edit]</em>");

    arrLength = current_vals.length;

    var addArray = [];
    var addArray2 = [];
    if(! flag)
    {
        $('#'+html_id).html(currentValHtml);
        $('#'+display_id)   
            .click(
                function(e) {
                    
                    if ($(this).length > 0) {                   
                        
                        // Remove the display elements:
                        $('#'+html_id).empty();
                        
                        var id = html_id;//$(this).get(0).id;
                        //id = id.replace(/display_/, "");
                        //if ($('#'+id).length == 0) {
                            var parentElement = $('#'+html_id);//$(this).parent();
                            var textTemp = generateCompoundArrayEdit(id, current_vals, propertyNames, propertyTypes, useSuggest, parentElement, valsArray);
                            
                            onAddCompoundRow(id,propertyNames, propertyTypes, useSuggest, null, valsArray);
                            //var text = $(textTemp);
                            //.append(text);
                            
                            //var id2 = fbSuggest(id,propertyType2,addArray, addArray2);
                            //var id_read = $(id2);
                            
                            $('#'+id).val($(this).html().substring(0, $(this).html().indexOf('<em>[Edit]</em>')))
                                                
                            $('#add_'+id).bind('click',
                                function (e,data){
                                    if ($(this).length > 0) {
                                        var id = $(this).get(0).id;
                                        
                                        onAddCompoundRow(id,propertyNames, propertyTypes, useSuggest, null, valsArray)
                                        //id2 = fbSuggest(id, propertyType2,addArray, addArray2);
                                        //id_read = $(id2);
                                        
                                    }
                                }
                            );
                            
                            $('#submit_'+id).bind('click',
                                function (e,data){
                                    if ($(this).length > 0) {
                                        var id = $(this).get(0).id;
                                        $("#tabbed-container").tabs({ disabled: [0, 1, 2, 3, 4] });
                                        document.body.style.cursor = "wait";
                                        onSubmitCompound(parent_topic_id,id, options, current_vals, type, propertyNames, propertyTypes, compoundPropertyType, compoundProperty, domain_used);
                                        // Create the button for syncing the reads with the written content:
                                        createSyncButton(topicName);
                                    }
                                return false;
                                }
                            );
                            $('#cancel_'+id).bind('click',
                                function (e,data){ 
                                $('#'+html_id).css({overflow:'hidden'});
                                    if ($(this).length > 0) {
                                        var id = $(this).get(0).id;
                                        onCancelCompound(id, options);
                                    }
                                }
                            );      
                    }
                }
        );  
    }
if (flag=='save')
{
        $('#'+html_id).html(currentValHtml);
        $('#'+display_id)   
            .click(
                function(e) {
                    
                    if ($(this).length > 0) {                   
                        
                        // Remove the display elements:
                        $('#'+html_id).empty();
                        
                        var id = html_id;//$(this).get(0).id;
                        //id = id.replace(/display_/, "");
                        //if ($('#'+id).length == 0) {
                            var parentElement = $('#'+html_id);//$(this).parent();
                            var textTemp = generateCompoundArrayEdit(id, current_vals, propertyNames, propertyTypes, useSuggest, parentElement, valsArray,true);
                            
                            onAddCompoundRow(id,propertyNames, propertyTypes, useSuggest, null, valsArray,flag);
                            //var text = $(textTemp);
                            //.append(text);
                            
                            //var id2 = fbSuggest(id,propertyType2,addArray, addArray2);
                            //var id_read = $(id2);
                            
                            $('#'+id).val($(this).html().substring(0, $(this).html().indexOf('<em>[Edit]</em>')))
                                                
                            $('#add_'+id).bind('click',
                                function (e,data){
                                    if ($(this).length > 0) {
                                        var id = $(this).get(0).id;
                                        
                                        onAddCompoundRow(id,propertyNames, propertyTypes, useSuggest, null, valsArray)
                                        //id2 = fbSuggest(id, propertyType2,addArray, addArray2);
                                        //id_read = $(id2);
                                        
                                    }
                                }
                            );
                            
                            $('#submit_'+id).bind('click',
                                function (e,data){
                                    if ($(this).length > 0) {
                                        var id = $(this).get(0).id;
                                        document.body.style.cursor = "wait";
                                            onSubmitCompound(parent_topic_id,id, options, current_vals, type, propertyNames, propertyTypes, compoundPropertyType, compoundProperty, domain_used,flag);                                      
                                            
                                        // Create the button for syncing the reads with the written content:
                                        createSyncButton(topicName);
                                    }
                                return false;
                                }
                            );              
                    }
                }
        );
        
}
if(flag && flag !='save'){
        // Remove the display elements:
            $('#'+html_id).html(currentValHtml);
            $('#'+html_id).empty();
            var id = html_id;//$(this).get(0).id;
            var parentElement = $('#'+html_id);//$(this).parent();
            var textTemp = generateCompoundArrayEdit(id, current_vals, propertyNames, propertyTypes, useSuggest, parentElement, valsArray,flag);
                onAddCompoundRow(id,propertyNames, propertyTypes, useSuggest, null, valsArray);
                            
                $('#'+id).val($('#'+html_id).html().substring(0, $('#'+html_id).html().indexOf('<em>[Edit]</em>')))
                                    
                $('#submit_'+id).bind('click',
                    function (e,data){
                        if ($(this).length > 0) {
                            var id = $(this).get(0).id;
                            var parent_id = id.replace('submit_', "");
                            $('#'+parent_id).fadeOut(1000, function () {
                                                                 
                            document.body.style.cursor = "wait";
                                
                                onSubmitCompound(parent_topic_id,id, options, current_vals, type, propertyNames, propertyTypes, compoundPropertyType, compoundProperty, domain_used,flag);                                                                  
                             // Create the button for syncing the reads with the written content:
                            createSyncButton(topicName);    
                                
                            });
                            
                        }


                    return false;
                    }
                );
}
}

// This function returns a string from the JSON code that can be used in the form element.
function createStringFromJSON_compound(vals,propertyNames){
    var s = '<table><thead><tr>';
    for(var a=0;a<propertyNames.length; a++){
        s += "<th>"+propertyNames[a]+"</th>"
    }
    s += "</tr></thead>"
    for(var i=0;i<vals.length; i++){
        var v = vals[i];
        // see if this value has a property name of interest
        s += "<tr>"
        for(var a=0;a<propertyNames.length; a++){
            var v_data_temp = v[propertyNames[a]];
            s += "<td>"
            
            if (v_data_temp != null) {
                var v_data = v_data_temp.name;
                if (typeof(v_data) != "undefined") {
                    if (v_data != null) {
                        
                        s += "<input type=\"text\" disabled=\"disabled\" id=\""+propertyNames[a]+"\" value=\""+v_data+"\"/>"
                    }else {
                        s += "<input type=\"text\" disabled=\"disabled\" id=\""+propertyNames[a]+"\" value=\"\"/>"
                    }
                }else {
                    
                    s += "<input type=\"text\" disabled=\"disabled\" id=\""+propertyNames[a]+"\" value=\""+v_data_temp+"\"/>"
                }
            }else {
                s += "<input type=\"text\" disabled=\"disabled\" id=\""+propertyNames[a]+"\" value=\"\"/>"
            }
            s += "</td>"
        }
        s += "</tr>"
    }
    s += "</table>"
    return s;
}

/**
 * Submits the user edited values to freebase.  A significant aspect of this function is comparing the user
 * edits to the previous set of current vals to determine which values should be added and removed.  NOTE:
 * currently removing values is not functional.
 * @param parent_topic_id       the freebase id of the parent topic
 */
function onSubmitCompound(parent_topic_id, id,options,  current_vals, topicType, propertyNames, propertyTypes, compoundPropertyType, compoundProperty, domain_used,flag){
    
    if($(this).length > 0) {
        
        // Get the new vals from the form:
        var parent_id = id.replace('submit_', "");
        var name=options.topicName;
        name=replaceAll(name, ' ', '-');
        name= name.replace(' ', '-');
        name = name.replace('.', '');
        name = name.replace(',', '');
        name = name.replace('&amp;', '');
        name = name.replace("'", '');
        
        var form = $('#form_'+parent_id);
        var rows = form.children().children().children().siblings();
        
        // Create an object to hold data that is to be added and that is to be removed:
        var vals_to_add = new Array();
        var vals_to_remove = new Array();
        
        // Go through each row and compare to the current vals.
        // If any val does not match up add it to the newVals
        // newPropertyNames and newPropertyTypes are used to keep track of existing information
        var newValsHTML = '';  // To be displayed after values are submitted
        var topic1_vals = Object();
        topic1_vals['data'] = Array();
        topic1_vals['type'] = compoundPropertyType;
        var topic2_vals = Object();
        topic2_vals['data'] = Array();
        
        // Each row is a new compound object.
        for (var i=0; i<rows.length-1; i++){
            
            // Get the html of the row:
            var row_index = i+1; // first row is the table headers
            var row_val = getElementParameters_html($('#row_'+row_index+'_'+parent_id));
            
            // If the row is created new, create a new element to add. 
            var add_new_compound_row = (row_val.create_new.toLowerCase()=='true')
            var row_object = null;
            if(add_new_compound_row){
                row_object = new Object();
                row_object['type'] = 'link';
                row_object['topic1'] = new Object();
                row_object['topic1']['guid'] = parent_topic_id;
                row_object['topic2'] = new Array();
                row_object['topic2'][0] = row_val;
                row_object['topic2'][0]['elements_to_add'] = new Array();
                row_object['topic2'][0]['topic1_property'] = compoundProperty;
                row_object['topic2'][0]['type'] = compoundPropertyType;
                row_object['topic2'][0]['force_create'] = 'true';
            }
            // Create an object to hold new objects to add
            var add_element_index = 0;
            var val_to_add = new Object();
            val_to_add['type'] = 'link';
            val_to_add['topic1'] = new Object();
            val_to_add['topic1']['guid'] = row_val.guid;
            val_to_add['topic2'] = new Array();
                        
            var current_vals_row = (i < current_vals.length ? current_vals[i] : null);      
            var row = rows[i];
            var elements = row["cells"];
            // Go through each element and see what needs to be added or removed
            
            for (var j=0; j<elements.length; j++){
                var element_id = '#'+parent_id+'_'+(i+1)+'_'+(j); 
                var element = getElementParameters_html($(element_id));
                    
                
                
                // If the element is primative then we have to get the name directly from the element:
                if(isPrimativeType(propertyTypes[j])){
                    element.name = $(element_id).val();
                }

                var add_element = false;
                var remove_element = false;
    
                // First see if the element is new:
                if(element.create_new.toLowerCase()=='true'){
                    add_element = true;
                } else {
                    
                    // Compare the element with the existing value
                    var current_comp_element = (current_vals_row != null ? current_vals_row[propertyNames[j]] : null);
                    // If the existing value does not exist, we need to add the element
                    if(current_comp_element == null){
                        if(element['name'].length>0){
                            add_element = true;
                        }
                    } else { // compare unique identifiers of the current value and the form value
                        // First see if it is a primative type:
                        if(isPrimativeType(propertyTypes[j])){
                            // Compare the names on the primative types:
                            var current_val_temp = (current_comp_element.length > 0 ? current_comp_element[0] : current_comp_element)
                            if(!(current_val_temp==element['name'])){
                                add_element = true; //adding the element will update the primative type
                            }                           
                        } else {
                            // HERE: Fix the case where current_comp_element == null
                            if(!(current_comp_element['guid']==element['guid'])){
                                //current_comp_element_guid = current_comp_element['guid'];
                                // Need to remove the old element and add the new one.
                                remove_element = true;
                                add_element = true;
                            }                                           
                        }
                    }
                    
                    //current_comp_element['guid']==comp_element.attr('topic_guid')
//                  var currentVal = (current_vals_row != null ? current_vals_row[propertyNames[j]] : null);
//                  if(currentVal['guid'] != element.name && element.name.length > 0){
//                      add_element = true;
//                      remove_element = false;                     
//                  }
                }
                // If we need to add the element:
                if(add_element){
                    var topic2 = val_to_add['topic2'];
                    topic2[add_element_index] = new Object();
                    val_to_add['topic2'][add_element_index] = element;              
                    val_to_add['topic2'][add_element_index]['topic1_property'] = compoundPropertyType.replace(/"/g,'') + '/' + propertyNames[j];                
                    val_to_add['topic2'][add_element_index]['type'] = element.type;
                    val_to_add['topic2'][add_element_index]['elements_to_add'] = new Array();               
                    val_to_add['topic2'][add_element_index]['force_create'] = 'false';                                  
                    add_element_index++;                                                                
                }
                // If we need to remove the element
                if(remove_element && typeof(compound_row)!='undefined'){
                    // Create an object to hold new objects to remove
                    var remove_element_index = 0;
                    var val_to_remove = new Object();
                    val_to_remove['type'] = 'unlink';
                    val_to_remove['topic1'] = new Object();
                    val_to_remove['topic1']['guid'] = compound_row.guid;
                    val_to_remove['topic2'] = new Object();
                    val_to_remove['topic2']['guid'] = current_comp_element_guid;
                    val_to_remove['topic2']['topic1_property'] = structure_element['topic1_property_full'];
                    val_to_remove['topic2']['type'] = comp_element_topic_type;
                    vals_to_remove.push(val_to_remove);                 
                }
            }
            // If we need to add a new compound row, add it to the vals_to_add
            if(add_new_compound_row){
                // If there are new elements to add, add them to the new compound row and commit the new row:
                if(val_to_add['topic2'].length > 0){
                    row_object['topic2'][0]['elements_to_add'].push(val_to_add);
                    vals_to_add.push(row_object);               
                }
            } else {
                // If we don't need to add a new compound row, but need to add the values, add the val_to_add object:
                if(val_to_add['topic2'].length > 0){
                    vals_to_add.push(val_to_add);
                }
            }
            
        }
        
        // create strings of the new data for an HTTP POST
        //var postCommand = '/topic_info/write_compound/';
        var post_command = '/topic_info/write_mixed/'; 
        
        
        // Replace the display form:    
        // remove the edit fields
        $('#'+parent_id).empty()
        // If we have any new values:
        perform_touch(domain_used);         
        if(vals_to_add.length > 0 || vals_to_remove.length > 0){    
            var transmit_data = new Object();   
            transmit_data["vals_to_add"] = JSON.stringify(vals_to_add);
            transmit_data["vals_to_remove"] = JSON.stringify(vals_to_remove);
            
            $.ajax({
                type: "POST",
                async:   false,
                url: post_command + parent_id + '/',
                data: transmit_data,
                success: function(m) {
                //  if (console && console.log) {
                //      console.log(m);
                //  }
                
                },
                error: function (xhr, desc, exceptionobj) {
},
                dataType: "text",
                cache: false
            });     
        }
        
        // Re-obtain the current vals from freebase and re-create the compoundElement
        perform_touch(domain_used); 
        perform_freebase_read(
            options.url_read,
            options.current_vals_q,
            function (msg) {
                
                var new_vals = msg.result && msg.result[0] ? msg.result[0] : null;
                
                var new_options = options;
                // Re-create the multiElement with the new values
                new_options.current_vals = new_vals[options.compoundProperty];
                if(flag){
                    
                    compoundElement(parent_id,new_options, domain_used,'save');
                    $('#'+parent_id).show();
                            var street= $('#street_address').val();
                            var city = $('#citytown').val();
                            var state = $('#state_province_region').val();
                            var postal_code = $('#postal_code').val();
                            
                            var address='';
                            if(typeof(street)!='undefined' && street!='')
                            {
                                address+=street+ ',';
                            }
                            if(typeof(city)!='undefined' && city!='')
                            {
                                address+=city+ ',';
                            }
                            if(typeof(state)!='undefined' && state!='')
                            {
                                address+=state+ ',';
                            }
                            if(typeof(postal_code)!='undefined' && postal_code!='')
                            {
                                address+=postal_code;
                            }
                            
                            if(address!='')
                            {
                                
                                if (GBrowserIsCompatible()) {
                                    map = new GMap2(document.getElementById('map_canvas_1'));
                                    geocoder = new GClientGeocoder();
                                    geocoder.getLatLng(
                                      address,
                                      function(point) {
                                        if (!point) {
                                          alert(address + " not found");
                                        } else {
                                          point_val = point;
                                          map.setCenter(point, 13);
                                          marker = new GMarker(point,{'draggable':true});
                                            map.addOverlay(marker);
                                            //marker.openInfoWindowHtml(address);     
                                        }
                                      }
                                    );          
                                    map.enableScrollWheelZoom();
                                }
                                $('#submit_'+name).removeAttr("disabled");
                            
                            }                   
                }
                else{
                    compoundElement(parent_id,new_options, domain_used);
                }
            },
            function(m){}
        );
                                
    }
    document.body.style.cursor="default";
}


function onCancelCompound(id, options) {
    if ($(this).length > 0) {
        id = id.replace(/cancel_/, "");

        // Remove the edit elements:
        $('#'+id).empty();
        
        // Recreate the display
        compoundElement(id,options)
        
        //$('#'+id).val($("#display_"+id).html().substring(0, $("#display_"+id).html().indexOf(' <em>[Edit]</em>')));
        //$('#display_'+id).toggle();
        //$('#form_'+id).toggle();
        return false;
    }               
}

/**
 * Generates the form for compound elements
 * 
 * @param html_id           The base html id to be used for the form
 * @param vals              The current set of vals used to populate the form
 * @param property_names    The names of the properties.  These are used to create the form headers.
 * @param property_types    
 * @param use_suggest       Whether or not use the freebase suggest in each element.
 * @param parent_element
 * @param val_arrays
 */
function generateCompoundArrayEdit(html_id, vals, property_names, property_types, use_suggest, parent_element, val_arrays,flag){
    
    // Remove the old elements:
    //parentElement.empty();
    
    // First generate the form and add it to the parent element.
    var textTemp ='<form id="form_' + html_id + '" name="form_' +html_id+'" >';
    textTemp += '<table>';
    textTemp += createPropertyRow(property_names);
    textTemp += '</table>'
    textTemp += '</form>';
    
    parent_element.append($(textTemp));
    if(flag)
    {
        $("#"+html_id).css({width:'800px'});
        
    }
    else
    {
        $("#"+html_id).css({width:'650px'});
        $("#"+html_id).css({overflow:'auto'});
    }
    // Next add the rows individually
    for(var i=0;i<vals.length; i++){
        var v = vals[i];
        val_arrays = onAddCompoundRow(html_id,property_names, property_types, use_suggest, v, val_arrays);
    }

    // Add the buttons:
    var form = $('#form_'+html_id);
    var table = form.children();
    if(flag)
    {
            var buttons = '<input type="submit" id="submit_'+html_id+'" value="Save and verify location on map" />'+
                '</form><div id="popup'+html_id+'" style="display:none"> </div>';
    }
    else
    {
    var buttons = '<input type="button" id="add_'+html_id+'" value="+"/>'+
                '<input type="submit" id="submit_'+html_id+'" value="Save" />'+
                '<input type="button" id="cancel_'+html_id+'" value="Cancel" /></form><div id="popup'+html_id+'" style="display:none"> </div>';
    }
    table.after($(buttons)) ;
}

function createPropertyRow(property_names){
    var s ='<thead><tr>';
    for(var a=0;a<property_names.length; a++){
        s+='<th>'+property_names[a]+'</th>';
    }
    s+='</tr></thead>'
    return s;   
}


/**
 * Add a compound row to the compound element
 * 
 * @param html_id
 * @param propertyNames
 * @param propertyTypes
 * @param useSuggest
 * @param rowVals
 * @param valsArray
 */
function onAddCompoundRow(html_id, property_names, property_types, use_suggest, row_vals, vals_array,flag) {
    
    // if the row_vals are null, then create a row of null for the vals and 
    if( !flag){
    var create_new_row = false;
    if(row_vals == null){
        create_new_row = true;
        row_vals = Object();
        for(var a=0; a<property_names.length; a++){
            row_vals[property_names[a]] = null;
        }
    }       

    // get to the rows of the table:        
    var siblings = $('#'+html_id).siblings();
    html_id = html_id.replace(/add_/,"");
    var form = $('#form_'+html_id);
    var rows = form.children().children().children();
            
    // generate a new id for the element
    var newID = 'row_'+ html_id + '_'+(rows.length);
    
    // Add a new row of null values:
    var rowNum = rows.length;
    var rowText = createCompoundRow(html_id, row_vals, property_names, property_types, rowNum, create_new_row);
    var anotherRow = jQuery(rowText); 
    var lastRow = $(rows[rows.length-1]);
    lastRow.after(anotherRow)
            
    fbSuggestCompoundRow(html_id, property_types, use_suggest, rowNum, row_vals.id);
    }
    
    else
    {
        var create_new_row = false;
        if(row_vals == null){
            create_new_row = true;
            row_vals = Object();
            for(var a=0; a<property_names.length; a++){
                row_vals[property_names[a]] = null;
            }
        }       
    
        // get to the rows of the table:        
        var siblings = $('#'+html_id).siblings();
        html_id = html_id.replace(/add_/,"");
        var form = $('#form_'+html_id);
        var rows = form.children().children().children();
                
        // generate a new id for the element
        var newID = 'row_'+ html_id + '_'+(rows.length);
        
        // Add a new row of null values:
        var rowNum = rows.length;
        var rowText = createCompoundRow(html_id, row_vals, property_names, property_types, rowNum, create_new_row,flag);
        var anotherRow = jQuery(rowText); 
        var lastRow = $(rows[rows.length-1]);
        lastRow.after(anotherRow)
                
        fbSuggestCompoundRow(html_id, property_types, use_suggest, rowNum, row_vals.id);
    }
    
}

/**
 * Creates a single compound object as a table row.
 * 
 * @param html_id
 * @param v
 * @param property_names
 * @param property_types
 * @param row_num
 */
function createCompoundRow(html_id, v, property_names, property_types, row_num, create_new_row,flag){
    
    // Create the html element of the row.
    var row_html_id = 'row_'+row_num+'_'+html_id; 
    var row_html_params = create_new_row ?
                    createHTMLParamsEmpty(row_html_id):
                    createHTMLParams(row_html_id, v.guid, v.id, '', v.type, false);
                    
    var s = '<tr '+row_html_params+' >';
    
    // Add all elements to the compound row.
if(!flag){
    for(var a=0;a<property_names.length; a++){
        var v_data = v[property_names[a]];
        var property_type = property_types[a];
        var html_id_full = html_id+'_'+row_num+'_'+a;
        
        var topic_name = '';
        var data_id = '';
        var data_guid = '';
        
        if(isPrimativeType(property_type)){
            topic_name = (v_data != null ? v_data : '');
            data_id = 'n/a';
            data_guid = 'n/a';
        } else {
            if(v_data == null || typeof(v_data)== "undefined"){
                v_data = Object();
                v_data.name = '';
                v_data.id = '';
                v_data.guid = '';
            }       
            topic_name =  (v_data.name != null || v_data.name=="undefined" ? v_data.name : '');
            data_id = v_data.id;
            data_guid = v_data.guid;
        }

        // Create the html to hold the element
        s+='<td>';
        s+='<input type="text"';
        s+=createHTMLParams(html_id_full, data_guid, data_id, topic_name, property_type, false);
        s+='></input>'  
        s+='</td>';
    }
}
else{
    
    /*for(var a=0;a<1; a++){
        alert('creating');
        var v_data = v[property_names[a]];
        var property_type = property_types[a];
        var html_id_full = html_id+'_'+row_num+'_'+a;
        
        var topic_name = '';
        var data_id = '';
        var data_guid = '';
        
        if(isPrimativeType(property_type)){
            topic_name = (v_data != null ? v_data : '');
            data_id = 'n/a';
            data_guid = 'n/a';
        } else {
            if(v_data == null || typeof(v_data)== "undefined"){
                v_data = Object();
                v_data.name = '';
                v_data.id = '';
                v_data.guid = '';
            }       
            topic_name =  (v_data.name != null || v_data.name=="undefined" ? v_data.name : '');
            data_id = v_data.id;
            data_guid = v_data.guid;
        }

        // Create the html to hold the element
        s+='<td>';
        s+='<input type="text"';
        s+=createHTMLParams(html_id_full, data_guid, data_id, topic_name, property_type, false);
        s+='></input>'  
        s+='</td>';
    }
*/
}
    s += '</tr>';
    return s;   
}
function fbSuggestCompoundRow(id, property_types, use_suggest, row_num, topic1_id) {
    
    var suggestNewText = 'Create new topic';
    for(var a=0;a<property_types.length; a++){
        //var id = propertyNames[a];
        var propertyType = property_types[a];
        if(propertyType != null && use_suggest[a]){
            var id_full = id+'_'+row_num+'_'+a;
                
            var options2 = {
                soft: true,
                suggest_new: suggestNewText,                        
                ac_param: {
                    type: propertyType
                    }
                };
        
            $('#' + id_full).freebaseSuggest(options2)
            .bind('fb-select', function(e, data) {
                $(this).attr("create_new", 'false');
                $(this).attr("guid", data.id);  // TODO: guid is depricated for topic_guid
                $(this).attr("topic_guid", data.id);
                $(this).attr("topic_name", data.id);
                $(this).attr("value", data.name);       
            })
            .bind('fb-select-new', function(e, data) { 
                $('#'+id_full).attr("create_new", 'true');
                $('#'+id_full).attr("guid", "n/a"); // TODO: guid is depricated for topic_guid
                $('#'+id_full).attr("topic_guid", "n/a");
                $('#'+id_full).attr("topic_name", $('#'+id_full).val());
                //createTopic(data.name,createType);
                //console.dir(data); 
            })
                        
        }
    }
}

/**
 * A bioventurist form element that allows users to enter data between multiple
 *  topics in a flexible manner.  For instance, we may want to link the parent
 *  topic with an array of topics (topic1), who also have a set of properties 
 *  we may want to set.
 * 
 * Parent topic ->
 *  topic1a -> topic2aa, topic2ab, topic2ac
 *  topic1a -> topic2ba, topic2bb, topic2bc
 *  topic1a -> topic2ca, topic2cb, topic2cc
 * 
 */
function mixedElement(html_id, data, parent_element){
    var parent_name = data.topic_name;
    var parent_id = data.topic_id;
    var parent_type = data.topic_type;
    var current_vals = data.current_vals;
    var parent_property = data.property;
    var element_structure = data.element_structure;
    var edit_blurb = data.edit_blurb;

    var display_id = 'display_'+html_id;
    var display_html = '<input type="button" id="'+display_id+'" value="Edit '+parent_name+'\'s '+edit_blurb+'"/>'
    
    var is_expanded = false;
    var htmlName = html_id;
    var valsArray = Object();
    valsArray.names = Array();
    valsArray.ids = Array();

    generateMixedElement(html_id, data, $("#"+html_id), disable=true);
    
    $('#'+html_id).append(display_html);
    $('#'+display_id)   
        .click(
            function(e) {
                if(!is_expanded){       
                    if ($(this).length > 0) {
                        var id = $(this).get(0).id;
                        id = id.replace(/span_/, "");
                        //if ($('#'+id).length == 0) {
                            var parent_element = $(this).parent();
                            parent_element.html("");
                            generateMixedElement(html_id, data, parent_element, disable=false);
                                                    
                        //} else {
                        //  $("#form_"+html_id).toggle();
                        //}
                        $('#'+id).focus();
                        $(this).toggle();   
                        is_expanded = true;
                    }
                    
                }
            }
    );
    
}

/**
 * Generates the form for a mixed element
 * @param html_id           the id of the form element to attach the mixed element to
 * @param data_options      contains much of the information about the mixed element to be created including:
 *                              i) the name of the topic being edited
 *                              ii) the data structure of the elements to be edited
 *                              iii) the current values
 * @param parent_element    the parent form element to attach the element to
 */
function generateMixedElement(html_id, data_options, parent_element, disable){
    
    var parent_name = data_options.topic_name;  // the name of the topic being edited
    var element_structure = data_options.element_structure;
    var current_vals = data_options.current_vals;
    // Get the structure of the data
    var topic1_type = element_structure['topic1_type'];
    var topic2 = element_structure['topic2'];
    
    // First generate the form and add it to the parent element.
    var textTemp ='<form id="form_' + html_id + '" name="form_' +html_id+'" >';
    textTemp += '<table id="table_' + html_id+'>';
    textTemp += createPropertyRow_MixedElement(element_structure);
    textTemp += '</table>'
    textTemp += '</form>';
    parent_element.append($(textTemp));
    
    // Next add the data into the table
    var table = $('#table_'+html_id);
    var table_rows = table.children();  // first row of the table will be the column names; concurrent rows are data
    for(var i=0;i<current_vals.length; i++){
        var v = current_vals[i];
        // The primary value is the first column
        // For each value add a new row:
        var row_id = html_id+'_'+'row_'+i;
        var new_row = '<tr id="'+row_id+'"></tr>'
        table_rows.append($(new_row));
        
        // Add the name of the value
        var primary_id = row_id+'_primary';
        var current_row = $('#'+row_id);
        primary_val = '<td>'
        primary_val +='<input type="text" topic_name="'+v.name+'" topic_type="'+v.type+'" value="'+v.name+'" id="'+primary_id +'"' +
                'topic_guid="'+v.guid+'" topic_id="'+v.id+'" create_new="false"></input>';
        
        primary_val += '</td>'
        current_row.append($(primary_val))
        //fbSuggestMulti(primary_id, topic1_type, 'Create new topic.');
        // Disable editing current primary values
        $("#"+primary_id).attr("disabled","disabled");
        
        // For each datatype for this row
        for(var j=0;j<topic2.length;j++){
            var topic2_data = topic2[j];
            // see what type of element it is:
            if(topic2_data['element_type']=='compound'){
                createCompoundMixedElement(row_id, j, current_row, v, element_structure, v.name, disable);
            } else if(topic2_data['element_type']=='overview_text'){
                var test = 0;
                createOverviewTextMixedElement(row_id, j, current_row, [], element_structure, v.name, disable);
            }
        }
    }

    // Add the buttons:
    if (!disable) {
        var form = $('#form_'+html_id);
        var table = form.children();
        var buttons = '<input type="button" id="add_'+html_id+'" value="'+element_structure.button_add_string+'"/>'+
                    '<input type="submit" id="submit_'+html_id+'" value="Save" />'+
                    '<input type="button" id="cancel_'+html_id+'" value="Cancel" /></form>';
        table.after($(buttons));
    
    
    // Bind actions to the buttons
    $('#add_'+html_id).bind('click',
        function (e,data){
            if ($(this).length > 0) {
                var html_id = $(this).get(0).id;
                html_id = html_id.replace(/add_/,"");
                addMixedElementRow(html_id, parent_name, element_structure, parent_element);
            }
        }
    );
    
    $('#submit_'+html_id).bind('click',
        function (e,data){
            if ($(this).length > 0) {
                var id = $(this).get(0).id;
                id = id.replace(/submit_/,"");
                $("#tabbed-container").tabs({ disabled: [0, 1, 2, 3, 4] });
                submitMixedElement(html_id, data_options, parent_element);
                // Remove the form elements
                $('#form_'+id).remove();
                // Re-create the multi-element
                 mixedElement(html_id, data_options, parent_element);
                 $('#'+id).toggle();
                 // Create the button for syncing the reads with the written content:
                 createSyncButton(parent_name);
                 $('#edit_'+id).attr("disabled","disabled");
                 
            }
            return false;
        }
    );

    $('#cancel_'+html_id).bind('click',
        function (e,data){ 
            if ($(this).length > 0) {
                var id = $(this).get(0).id;
                id = id.replace(/cancel_/,"");
                // Remove the form elements
                $('#form_'+id).remove();
                // Re-create the multi-element
                 mixedElement(html_id, data_options, parent_element);
                 $('#'+id).toggle();
            }
        }
    );
    }

}

/**
 * Adds a Mixed Element Row
 * @param html_id           the id of the form element to attach the mixed element to
 * @param parent_name       the name of the topic being edited
 * @param element_structure the data structure of the elements to be edited
 * @param parent_element    the parent form element to attach the element to
 */
function addMixedElementRow(html_id, parent_name, element_structure, parent_element){
    
    // Get the structure of the data
    var topic1_type = element_structure['topic1_type'];
    var topic2 = element_structure['topic2'];
    
    // get the table_rows
    var table = $('#table_'+html_id);
    var table_rows = table.children();
            
    // Find the last of the table:
    var more_elements = true;
    var last_known_element = 0;
    while(more_elements){
        var row = $('#'+html_id+'_row_'+last_known_element);        
        if(row.length==0){ // no more values
            more_elements = false;
        } else {
            last_known_element++;   
        }
    }
        
    // The primary value is the first column
    // For each value add a new row:
    var row_id = html_id+'_'+'row_'+last_known_element;
    var new_row = '<tr id="'+row_id+'"></tr>'
    table_rows.append($(new_row));
    
    // Add the name of the value
    var primary_id = row_id+'_primary';
    var current_row = $('#'+row_id);    
    var primary_val = '<td><input type="text"'+createHTMLParams(primary_id,'','','', '', false)+'</input></td>';
    current_row.append($(primary_val));
    // Add the freebase suggest
    fbSuggestMulti(primary_id, topic1_type, 'Create new topic.');
    
    // For each datatype for this row
    for(var j=0;j<topic2.length;j++){
        var topic2_data = topic2[j];
        // see what type of element it is:
        if(topic2_data['element_type']=='compound'){
            createCompoundMixedElement(row_id, j, current_row, [], element_structure, "");
        } else if(topic2_data['element_type']=='overview_text'){
            var test = 0;
            createOverviewTextMixedElement(row_id, j, current_row, [], element_structure, "");
        }
    }
}

/**
 * Creates a compound component for a Mixed element
 * @param row_id            the html id of the Mixed element row
 * @param col_index         the compount component's column index within the Mixed element
 * @param current_row       the htlm element of the Mixed element row
 * @param current_val       the current values to populate the element
 * @param element_structure the data structure of the elements to be edited
 * @param parent_name       the name of topic linking to this compound component
 */
function createCompoundMixedElement(row_id, col_index, current_row, current_val, element_structure, parent_name, disable){
    // Create a new table for compound elements:
    var compound_table_id = row_id+'_col_'+col_index;
    //var topic2_data_string = JSON.stringify(topic2_data);
    var compound_table_html = '<table id="'+compound_table_id+'"></table>'
    current_row.append($(compound_table_html));
    var compound_table = $('#'+compound_table_id);
    //compound_table.append($('<br></br>'))
    
    var topic2_data = element_structure['topic2'][col_index];
    // Get the data values for this compound element
    var compound_datas = (typeof(current_val[topic2_data['topic1_property']])!='undefined' ? current_val[topic2_data['topic1_property']] : []); 
    
    // For each compound_data add a new row to the compound_table:
    var data_added = false;
    for(var k=0;k<compound_datas.length; k++){
        data_added = true;
        var compound_row_id = compound_table_id+'_row_'+k;
        var compound_data = compound_datas[k];
        var compound_row_html = '<tr '+createHTMLParams(compound_row_id, compound_data.guid, compound_data.id, compound_data.name, '', false)
                                +'element_num="'+k+'"></tr>';
        compound_table.append($(compound_row_html));
        var compound_row = $('#'+compound_row_id);
        
        // Add each compound_element to the row
        // Get element via the structured element               
        // get all of the elements and add them to the table:
        var compound_element_types = topic2_data['elements'];
        for(var h=0;h<compound_element_types.length; h++){
            var element_type = compound_element_types[h];
            if(!element_type['is_topic1']){ // don't add reciprocal properties
                var compound_element = compound_data[element_type['topic1_property']];
                var compound_type = element_type['type'];
                var compound_element_id = compound_row_id+'_col_'+h;
                if (!disable) {
                    var compound_element_html = '<td><input type="text"';
                }else {
                    var compound_element_html = '<td><input disabled="disabled" type="text" id="'+compound_element_id+'"';
                }
                
                if(compound_element!= null){
                    compound_element_html += createHTMLParams(compound_element_id, compound_element.guid, compound_element.id, compound_element.name, '', false);
                } else {
                    compound_element_html += createHTMLParamsEmpty(compound_element_id);
                }
                compound_element_html += '></input></td>';
                compound_row.append($(compound_element_html));
                // Add the freebase suggest
                fbSuggestMulti(compound_element_id, compound_type, 'Create new topic.');
            }
        }
    }
    // If there is no data added, add a blank set of fields
    if(!data_added){
        addMixedCompoundRow(compound_table_id, current_val, element_structure, k);
    }               

    // Create add buttons
    if (!disable) {
        var buttons = '<input type="button" id="add_'+compound_table_id+'" element_num="'+col_index+'" value="'+topic2_data.button_add_string+' for '+parent_name+'"/>';
        compound_table.append($(buttons));
        $('#add_'+compound_table_id).bind('click',
            function (e,data){
                if ($(this).length > 0) {
                    var id = $(this).get(0).id;
                    id = id.replace(/add_/,"");
                    var element_num =parseFloat(this.getAttribute('element_num'));
                    addMixedCompoundRow(id, current_val, element_structure,element_num)             
                }
            }
        );  
    }
}

function createOverviewTextMixedElement(row_id, col_index, current_row, current_val, element_structure, parent_name){
    // Andrey: use this function to build our form elements for each row:
    var test = 0;
}

/**
 * Adds a row to the compound component of the mixed element
 * @param compound_table_id the html id compound component
 * @param topic1            the JSON data structure of the current value
 * @param element_structure the data structure of the elements to be edited
 * @param element_index     
 */
function addMixedCompoundRow(compound_table_id, topic1, element_structure, element_index){
    var compound_table = $('#'+compound_table_id);
    var table_id = compound_table.attr('id');
    var topic2_data = element_structure['topic2'][element_index];
    
    // Find the last row of the compound_table:
    var more_elements = true;
    var last_known_element = 0;
    while(more_elements){
        var row_id = table_id+'_row_'+last_known_element;
        var row = $('#'+row_id);
        if(row.length==0){ // no more values
            more_elements = false;
        } else {
            last_known_element++;   
        }
    }
    
    // add the element after the last element
    var row_id = table_id+'_row_'+last_known_element;
    //var compound_row_html = '<tr id="'+row_id+'"><tr>';
    var compound_row_html = '<tr '+createHTMLParamsEmpty(row_id)+'></tr>'
    compound_table.append($(compound_row_html));
    var compound_row = $('#'+row_id);

    // Add each compound_element to the row
    // Get element via the structured element               
    var compound_element_types = topic2_data['elements'];
    for(var h=0;h<compound_element_types.length; h++){
        var element_type = compound_element_types[h];
        var compound_type = element_type['type'];           
        var compound_element_id = row_id+'_col_'+h;         
        
        if(!element_type['is_topic1']){ // don't add reciprocal properties
            var compound_element_html = '<td><input type="text"'+createHTMLParamsEmpty(compound_element_id)+'></input></td>'        
            compound_row.append($(compound_element_html));
            // Add the freebase suggest
            fbSuggestMulti(compound_element_id, compound_type, 'Create new topic.');

        } else {
            //compound_element_html += '<td><input type="hidden"'+createHTMLParams(compound_element_id, topic1['guid'], topic1['id'], topic1['name'], topic1['type'], false)+'></input></td>'
        }
        
    }       
}


/**
 * Creates the column headers for a mixed element form
 * 
 * @param element_structure the structure of the element.  For example:
 *                           [enter example element here]   
 */
function createPropertyRow_MixedElement(element_structure){
    var s ='<tr>';
    // Add the topic1 property column names
    var topic1_property_name = element_structure.topic1_html_property_name;
    s+= '<th>'+topic1_property_name+'</th>'
    
    // Add all of remaning column names
    var topic2_elements = element_structure.topic2;
    for(var i=0;i<topic2_elements.length; i++){
        var topic2_element = topic2_elements[i];
        
        // See if it is a compound element
        if(topic2_element.element_type == 'compound'){
            // Compound elements are represented as tables:
            s+='<td><table><tr>';
            // Go through all of the compound properties:
            var compound_elements = topic2_element.elements;
            for(var j=0;j<compound_elements.length;j++){
                var compound_element = compound_elements[j];
                if(!compound_element.is_topic1){ //only display non-recirocal properties
                    s+='<th>'+compound_element.html_property_name+'</th>';
                } else {
                    //s+='<td WIDTH=200 TYPE=HIDDEN>'+compound_element.html_property_name+'</td>';
                } 
            }
            s+='</tr></table></td>'
        } else { 
            //There isn't a case other than compound element yet.
        }       
    }
    s+='</tr>'
    return s;   
}

/**
 * Submits the user edited values to freebase.  A significant aspect of this function is comparing the user
 * edits to the previous set of current vals to determine which values should be added and removed.  NOTE:
 * currently removing values is not functional.
 * @param html_id           the html_id of the Mixed element
 * @param data_options      contains much of the information about the mixed element to be created including:
 *                              i) the name of the topic being edited
 *                              ii) the data structure of the elements to be edited
 *                              iii) the current values
 * @param parent_element    the html object of the element containing this value
 */
function submitMixedElement(html_id, data, parent_element){
    var post_command = '/topic_info/write_mixed/'; 
    
    var parent_name = data.topic_name;
    var parent_id = data.topic_id;
    var parent_type = data.topic_type;
    var current_vals = data.current_vals;
    var element_structure = data.element_structure;
    var structure_topic2s = element_structure['topic2'];
    var parent_property = element_structure['parent_property'];
    var topic1_type = element_structure['topic1_type']
    
    // Holds the data for user entered and removed data
    var vals_to_add = new Array();
    var vals_to_remove = new Array();
    
    // Iterate through the rows of the element structure and retrieve user entered data 
    var more_primary_elements = true;
    var row_index = 0;
    while(more_primary_elements){
        var row_id = html_id+'_row_'+row_index;
        var row = $('#'+row_id);
        
        // Obtain the value before editing;
        var current_primary = null;
        if(current_vals.length>row_index){ // Val exists;
            current_primary = current_vals[row_index];
        }
        
        if(row.length==0){ // no more values
            more_primary_elements = false;
        } else {
            // Get the primary value:
            var primary_id = row_id + '_primary';
            var primary_html = $('#'+primary_id);
            var primary = getElementParameters_html(primary_html);
            var primary_object = null;
            primary_object = new Object();
            primary_object['type'] = 'link';
            primary_object['topic1'] = new Object();
            primary_object['topic1']['guid'] = parent_id;
            //new_compound_object['topic1']['property'] = e_topic1_property;
            primary_object['topic2'] = new Array();
            primary_object['topic2'][0] = primary;
            primary_object['topic2'][0]['elements_to_add'] = new Array();
            primary_object['topic2'][0]['topic1_property'] = parent_property;
            primary_object['topic2'][0]['type'] = element_structure['topic1_type']
            primary_object['topic2'][0]['force_create'] = 'false';
            
            var add_primary = false;
            if(primary.name.length>0){ // if the val exists in the form
                // Compare with the current val
                var remove_primary = false
                if(current_primary != null){ // a current value exits and needs to be compared for editing
                    // Compare the unique identifiers
                    if(!current_primary['guid']==primary.guid){ // The topics are not the same
                        remove_primary = true;
                        add_primary = true;                     
                    }
                } else if(primary.name.length > 0) { // this is a new value and needs to be added if there is a value 
                    add_primary = true;
                } 
                if(remove_primary){ // remove the existing primary value
                    var val_to_remove = new Object();
                    val_to_remove['type'] = 'unlink';
                    val_to_remove['topic1'] = new Object();
                    val_to_remove['topic1']['guid'] = parent_id;
                    val_to_remove['topic2'] = new Array();
                    val_to_remove['topic2'][0] = new Object();
                    val_to_remove['topic2'][0]['topic1_property'] = parent_property;
                    val_to_remove['topic2'][0]['type'] = element_structure['topic1_type']
                    val_to_remove['topic2'][0]['elements_to_add'] = new Array();
                    val_to_remove['topic2'][0]['force_create'] = 'false';
                    vals_to_remove.push(val_to_remove); 
                }
                if(add_primary){ // add the new primary value
                    
                    vals_to_add.push(primary_object);
                }
            
                // Iterate through the rest of the column
                var more_cols = true;
                var col_index = 0;
                while(more_cols){
                    var col_id = row_id+'_col_'+col_index;
                    var col_element = $('#'+col_id);
                    if(col_element.length==0){ // no more col indexes
                        more_cols = false;
                    } else {
                        // Determine what type of element this is
                        var structure_topic2 = structure_topic2s[col_index]; 
                        var e_type = structure_topic2['element_type'];
                        var e_topic1_property = structure_topic2['topic1_property'];
                        var primary_property = structure_topic2['topic1_property'];                 
                        if(e_type=='compound'){
                            // Retrieve the compound elements:
                            retrieveMixedCompoundElements(col_id, current_primary, primary_property, vals_to_add, vals_to_remove, primary_object, add_primary, e_topic1_property, structure_topic2);
                        }
                    }
                    col_index++;
                }
            }
        }
        row_index++;
    }

    
    // If we have any new values:
    if(vals_to_add.length > 0 || vals_to_remove.length > 0){    
        var transmit_data = new Object();   
        transmit_data["vals_to_add"] = JSON.stringify(vals_to_add);
        transmit_data["vals_to_remove"] = JSON.stringify(vals_to_remove);
        $.ajax({
            type: "POST",
            url: post_command + parent_id + '/',
            data: transmit_data,
            success: function(m) {
                //if (console && console.log) {
                //  console.log(m);
                //}
            },
            error: function(m) {
            },
            dataType: "text",
            cache: false
        });     
    }       
    
    

}

/**
 * Retrieve's and compares the user html edits to the previous current set of values.
 * @param col_id            the html id of the compound component of the Mixed element 
 * @param current_primary   a JSON object of the current primary value of the Mixed element
 * @param primary_property  the property linking the primary object to this compound object
 * @param vals_to_add       an array to hold any new values that are to be added
 * @param primary           a JSON object of a 
 * HERE
 */
function retrieveMixedCompoundElements(col_id, current_primary, primary_property, vals_to_add, vals_to_remove, primary, add_primary, e_topic1_property, structure_topic2){
    // Iterate through the rows and elements of the compound element
    var compound_elements_to_add = new Array(); // hold any compound elements that need to be added
    var more_comp_rows = true;
    var structure_elements = structure_topic2['elements'];
    var topic2_type = structure_topic2['type'];
    
    var new_compound_object = null;
    
    // Iterate through the rows of the compound element
    var comp_row_index = 0;
    var add_comp_row_index = 0;
    for(var z=0; more_comp_rows; z++){
        
        // obtain the row from the html form
        var comp_id = col_id + '_row_'+comp_row_index;
        var comp_row = $('#'+comp_id);
        if(comp_row.length==0){ // If no more rows exist, exit the loop
            more_comp_rows = false;
        } else {
            var add_compound_row = false;
            var comp_current_row = null;
            var add_new_compound_row = false;

            // Obtain the compound_row from the HTML element
            var compound_row = getElementParameters_html(comp_row);

            // Create a new compound object if the html determines it is a new object:                  
            var cr_create_new = ''+ compound_row["create_new"];
            if(cr_create_new.toLowerCase()=='true'){
                new_compound_object = new Object();
                new_compound_object['type'] = 'link';
                new_compound_object['topic1'] = new Object();
                new_compound_object['topic1']['guid'] = primary['topic1']['guid'];
                new_compound_object['topic2'] = new Array();
                var new_compound_index = new_compound_object['topic2'].length; 
                new_compound_object['topic2'][new_compound_index] = compound_row;
                new_compound_object['topic2'][new_compound_index]['type'] = topic2_type;
                new_compound_object['topic2'][new_compound_index]['topic1_property'] = structure_topic2['topic1_property'];
                new_compound_object['topic2'][new_compound_index]['elements_to_add'] = new Array();
                new_compound_object['topic2'][new_compound_index]['force_create'] = 'true';
                add_new_compound_row = true;
            }
            
            /*
            var primary_created_new = (current_primary == null);
            if(primary_created_new){
                add_new_compound_row = true;
            } 
            
            else {
                // potentially add a new row if the primary does not have any values and the user has
                // entered values.
                var new_val = getMixedElementParameters(comp_row);
                var user_entered_val = (new_val.name.length > 0);
                var current_primary_has_no_vals = (current_primary[primary_property].length<=comp_row_index); 
                add_new_compound_row = user_entered_val && current_primary_has_no_vals; 
            }
            */
            //if(col_id=='span_therapeutic_pipeline_row_3_col_0'){alert('2')}
             
            // Obtain the previous values of the compound row.
            if(add_new_compound_row){ 
                comp_current_row = [];
            } else { // If there are as many current values and new values, compare identifiers.
                comp_current_row = (current_primary[primary_property].length > comp_row_index ? current_primary[primary_property][comp_row_index] : null) 
            }
            
            // For each compound row, iterate across all elements
            // Get the structure from the element_structure
            var e_structs = structure_topic2['elements'];
            
            // Create an object to hold new objects to add
            var add_element_index = 0;
            var val_to_add = new Object();
            val_to_add['type'] = 'link';
            val_to_add['topic1'] = new Object();
            val_to_add['topic1']['guid'] = compound_row.guid;
            //val_to_add['topic1']['property'] = e_topic1_property;
            val_to_add['topic2'] = new Array();
                        
            // Iterate through all elements
            for(var i=0;i<e_structs.length;i++){
                //if(col_id=='span_therapeutic_pipeline_row_3_col_0'){alert('2_'+i)}
            
                var structure_element = structure_elements[i];      
                var comp_element_topic_type = structure_element['type']
                var e = e_structs[i]; // the elements for the row
                var e_property = e['topic1_property'];
                var add_element = false;
                var remove_element = false;
                var comp_element_id = comp_id+'_col_'+i;
                var comp_element = $('#'+comp_element_id);
                var current_comp_element_guid = null;
                var compound_element = null; 
                if(!e['is_topic1']){ // there are not form elements for reciprocal properties                                                                                               
                    if(comp_element.length>0 && comp_element.val().length>0){
                        compound_element = getElementParameters_html(comp_element);
                        // Compare with current vals
                        if(!(add_primary||add_new_compound_row)){ //not a new primary val
                        
                            // Compare the element with the existing value
                            var current_comp_element = comp_current_row[e_property];
                            // If the existing value does not exist, we need to add the element
                            if(current_comp_element == null){
                                add_element = true;
                            } else { // compare unique identifiers of the current value and the form value   
                                if(!(current_comp_element['guid']==comp_element.attr('topic_guid'))){
                                    current_comp_element_guid = current_comp_element['guid'];
                                    // Need to remove the old element and add the new one.
                                    remove_element = true;
                                    add_element = true;
                                }                                           
                            }
                        } else { //data added to a new primary val
                            add_element = true;
                        }
                    }
                } else {
                    if(add_primary){
                        compound_element = compound_row;
                    }
                    else if(add_new_compound_row){ // If the property is a reciprocal add the primary property
                        //var current_comp_element = comp_current_row[e_property];
                        compound_element = getElementParameters_object(current_primary);
                        add_element = true;
                    }
                }
                //if(col_id=='span_therapeutic_pipeline_row_3_col_0'){alert('3 ' + val_to_add.toSource() + ' : add_element = ' + add_element)}
                
                if(add_element){ // add the new values to the temporary object, val_to_add
                    //alert('adding element : i='+i+ ' add_element_index = ' + add_element_index);
                    val_to_add['topic2'][add_element_index] = compound_element;             
                    val_to_add['topic2'][add_element_index]['topic1_property'] = structure_element['topic1_property_full'];             
                    val_to_add['topic2'][add_element_index]['type'] = comp_element_topic_type;
                    val_to_add['topic2'][add_element_index]['elements_to_add'] = new Array();               
                    val_to_add['topic2'][add_element_index]['force_create'] = 'false';                                  
                    add_element_index++;                                                                
                                
                }
                if(remove_element){ // remove the value
                
                    // Create an object to hold new objects to remove
                    var remove_element_index = 0;
                    var val_to_remove = new Object();
                    val_to_remove['type'] = 'unlink';
                    val_to_remove['topic1'] = new Object();
                    val_to_remove['topic1']['guid'] = compound_row.guid;
                    val_to_remove['topic2'] = new Object();
                    val_to_remove['topic2']['guid'] = current_comp_element_guid;
                    val_to_remove['topic2']['topic1_property'] = structure_element['topic1_property_full'];
                    val_to_remove['topic2']['type'] = comp_element_topic_type;
                    vals_to_remove.push(val_to_remove);
                }
                
            }
            // If there is a new compound row, add the new element to this row:
            if(add_new_compound_row){
                //alert('pushing element on new_compound.  val_to_add = '+JSON.stringify(val_to_add));
                var new_compound_topic2 = new_compound_object['topic2']; 
                new_compound_topic2[new_compound_index]['elements_to_add'].push(val_to_add);
                //alert("pushed.  new_compound_object['topic2'][new_compound_index]['elements_to_add'] = "+JSON.stringify(new_compound_object['topic2'][new_compound_index]['elements_to_add']));
            }
            
            //if(col_id=='span_therapeutic_pipeline_row_3_col_0'){alert('5')}
                
            // If the compound row is new, add the new element to the row
            // HERE
            if(val_to_add['topic2'].length>0){
                if(new_compound_object != null){
                    add_compound_row = true;  // Add the compound row
                    //new_compound_object['topic2'][add_comp_row_index]['elements_to_add'].push(val_to_add);
                } else { //Otherwise add the to be created compound elements directly to the new values
                    vals_to_add.push(val_to_add);                                                                                       
                }
            }

//          if(val_to_remove['topic2'].length){         
//              vals_to_remove.push(val_to_remove);
//          }                           
            // If the primary element was created new add the new_compound_obects to the primary value's arrays
            if(add_primary && add_compound_row){
                //here is that primary['topic2'] == undefined.
                primary['topic2'][0]['elements_to_add'].push(new_compound_object);
            } 
            //if(col_id=='span_therapeutic_pipeline_row_3_col_0'){alert('9')}
            else if(add_compound_row) { // Add the element directly to the parent array
                vals_to_add.push(new_compound_object);
            }                                                           
        }
        comp_row_index++;
    }

}

/**
 * Retrieves values from the html elements
 * 
 * @param html_element the element containing the following attributes:
 *              - guid          the topic unique identifier
 *              - id            the topic identifier
 *              - name          the topic name
 *              - type          the topic type
 *              - create_new    whether the topic should be created new or not
 * 
 * @return returns an object containing these types
 */
function getElementParameters_html(html_element){
    var element = new Object();
    element.guid = html_element.attr('topic_guid');
    element.id = html_element.attr('topic_id');
    element.type = html_element.attr('topic_type');
    element.name = html_element.attr('topic_name');
    element.create_new = html_element.attr('create_new');
    element.elements_to_add = new Array();
    return element;
}

function getElementParameters_object(val){
    var element = new Object();
    element.guid = val.guid;
    element.id = val.id;
    element.type = val.type;
    element.name = val.name;
    element.create_new = 'false';
    element.elements_to_add = new Array();
    return element;
}


/**
 * Generates the standard reqired set of pararmeters for mixed elements
 * 
 * @param html_id       the id of the html element
 * @param topic_guid    the topic's unique identifier
 * @param topic_id      the topic's identifier
 * @param topic_name    the topic's name
 * @param topic_type    the topic's type
 * @param create_new    whether the topic is created new or not
 * 
 * By default, the html value is set to the topic_name
 * 
 * @return a string of parameters that can be used inside an html tag.
 */
function createHTMLParams(html_id, topic_guid, topic_id, topic_name, topic_type, create_new){
    var s = ' ';
    s += 'value="'+topic_name+'"';
    s += 'id="'+html_id+'"';
    s += 'topic_guid="'+topic_guid+'"';
    s += 'topic_id="'+topic_id+'"';
    s += 'topic_name="'+topic_name+'"';
    s += 'topic_type="'+topic_type+'"';
    s += 'create_new="'+create_new+'"';
    return s;   
}

function createHTMLParamsEmpty(html_id){
    return createHTMLParams(html_id,'', '', '', '', true);
}


function onCancelMixed(id,not_editing_html) {
    if ($(this).length > 0) {
        $('#'+id).html(edit_html);
        //$('#'+id).val($("#span_"+id).html(not_editing_html));
        $('#span_'+id).toggle();
        $('#form_'+id).toggle();
        return false;
    }               
}



function fbSuggestMultiRow(id, vals, property_type) {
    
    for(var a=0;a<vals.length; a++){
        var id_full = id+'_'+a;
        fbSuggestMulti(id_full, property_type,'Create new topic');
    }
}

/* 
*  
 */
function fbSuggestMulti(id_full, property_type, suggestNewText) {
    var createType = property_type;

    var options2 = {
        soft: true,
        suggest_new: suggestNewText,
        ac_param: {
            type: property_type
            }
        };
    $('#' + id_full).freebaseSuggest(options2)
    .bind('fb-select', function(e, data) {
                            
        $(this).attr("create_new", 'false');
        $(this).attr("guid", data.id);  // TODO: guid is depricated for topic_guid
        $(this).attr("topic_guid", data.id);
        $(this).attr("topic_name", data.id);
        $(this).attr("value", data.name);   
        $('#'+id_full).attr("data_val", data.name);
        })
    .bind('fb-select-new', function(e, data) { 
                                    
        $('#'+id_full).attr("create_new", 'true');
        $('#'+id_full).attr("guid", "n/a"); // TODO: guid is depricated for topic_guid
        $('#'+id_full).attr("topic_guid", "n/a");
        $('#'+id_full).attr("topic_name", $('#'+id_full).val());
        //createTopic(data.name,createType);
        //console.dir(data); 
        })
    /*.blur(function (){
        // See if the user has entered a value via the search suggest:
        var guid = $('#'+id_full).attr("guid");  // no choice is selected
        var val = $('#'+id_full).attr("value");  // a value has been started
        
        if(typeof(guid) == "undefined" && val.length > 0){ // a value has not been entered yet
            //alert('Either select a choice, or click "Create new topic", from the drop-down menu.');
        }
        
    })*/;
        
        $('#'+id_full).blur(function (){
            var guid = $('#'+id_full).attr("data_val");
            if(guid == ""){
                $('#tooltip'+id_full).show();
            } else {
                $('#'+id_full).attr("data_val", "");
            }
        });
        $('#'+id_full).focus(function (){
            $('#tooltip'+id_full).hide();
            
        });
    
}

/*******************************************
SINGLE_ELEMENT_COMPOUND (sec)
    This is a simpler compound element 
    that allows users to enter data into a single text field
    that, when submitted, creates and links a compound topic.
    (e.g. website of a topic)
********************************************/
// Creates html for a sec element
function sec_element_html(id, value_name, current_val){
    var s = '<table>';
    s += '<tr>';
    s += '<td>'+value_name+':</td>';
    s += '<td><input type="text" name="" value="'+current_val+'" id="secID_'+id+'"></input></td>';
    s += '</tr>';
    s += '</table>'; 
    return s;
}

// Submits the results for an sec element
function submit_sec_element(value, html_id, topic_name, parent_topic_id, properties){
    
    // THIS FUNCTION IS BROKEN!! -JT NEED TO FIX
    
    // create strings of the new data for an HTTP POST
    var postCommand = '/topic_info/write_compound/';
    
    var topic1_vals = Object();
    topic1_vals['data'] = Array();
    topic1_vals['type'] = compoundPropertyType;
    var topic2_vals = Object();
    topic2_vals['data'] = Array();
    
    
    var topic1_index = topic1_vals['data'].length;
    var topic2_index = topic2_vals['data'].length;
                        // add topic1's info
                        topic1_vals['data'][topic1_index] = Object();
                        topic1_vals['data'][topic1_index]['id'] = topic1_id;
                        topic1_vals['data'][topic1_index]['property_name'] = propertyNames[j];
                        topic1_vals['data'][topic1_index]['property_type'] = propertyTypes[j];
                        // add topic2's info
                        topic2_vals['data'][topic2_index] = Object();
                        topic2_vals['data'][topic2_index]['val'] = topic2_val;
                        topic2_vals['data'][topic2_index]['id'] = topic2_id;
                        topic2_vals['data'][topic2_index]['row_index'] = i;
                        topic2_vals['data'][topic2_index]['create_new'] = element.attr('create_new');
                        topic2_vals['data'][topic2_index]['create_type'] = '"'+propertyTypes[j]+'"';  
    
    
    
    //var topic1_ids_string = properties.topic1_ids.join("+++");//'undefined';//topic1_ids.join("+++");
    //var topic2_vals_string = value;//topic2_vals.join("+++");
    //var topic2_ids_string = 'n/a';//topic2_ids.join("+++");
    //var topic1_property_types = properties.topic1_property_types.join("+++");//'/type/uri';//newPropertyTypes.join("+++");
    //var topic1_property_names = properties.topic1_property_names.join("+++");//'uri';//newPropertyNames.join("+++");
    //var topic2_row_indexes_string = '0';//topic2_row_indexes.join("+++");
    //var topic2_create_new_string = 'false';//topic2_newTopicBools.join("+++");
    //var topic2_create_type_string = properties.topic2_create_type_string.join("+++");//'/type/uri';//topic2_createType.join("+++");
    
    //var compoundPropertyType = properties.compound_property_type;//"/common/webpage"
    //var compoundProperty = properties.compound_property;//"/common/topic/webpage"

    var data = Object();
    //data["parent_topic_id"] = parent_topic_id;    
    //data["id_rep"] = "submit_"+html_id;
    //data["topic1_ids"] = topic1_ids_string;
    //data["topic1_type"] = compoundPropertyType;
    //data["topic1_property_types"] = topic1_property_types;
    //data["topic1_property_names"] = topic1_property_names;
    //data["parent_property"] = compoundProperty;
    //data["topic2_vals"] = topic2_vals_string;
    //data["topic2_ids"] = topic2_ids_string;
    //data["topic2_row_indexes"] = topic2_row_indexes_string;
    //data["topic2_create_new"] = topic2_create_new_string;
    //data["topic2_create_type"] = topic2_create_type_string;
    
            objects["parent_topic_id"] = parent_topic_id;   
        objects["id_rep"] = id;
        objects["parent_property"] = compoundProperty;
        objects["topic1_vals"] = JSON.stringify(topic1_vals);
        objects["topic2_vals"] = JSON.stringify(topic2_vals);
    
    
    // Post the command to django:
    $.ajax({
        type: "POST",
        url: postCommand + topic_name+ '/',
        data: data,
        success: function(m) {
        //  if (console && console.log) {
        //      console.log(m);
        //  }
        },
        error: function(m) {
        },
        dataType: "text",
        cache: false
    });     
    
}

/*******************************************
HELPER_FUNCTIONS
********************************************/
function createSyncButton(topic_name){
    // Create the sync button if one does not already exist
    var syncB = '<BUTTON TYPE=SUBMIT HEIGHT=97 WIDTH=350 ALT="Starflower" ALIGN="ABSMIDDLE"> <STRONG>Return to '+topic_name+'</STRONG></BUTTON>'
    if($('#edit_sync').children().length == 0) {
        $('#edit_sync')
            .append($(syncB))
            .click(
                function(e) {
                    location.href = '';                 
                })
    }           
        
}

function isPrimativeType(type){
    if(type == "/type/text"){
        return true;
    } else if (type == "/type/uri"){
        return true;
    } else if (type == "/type/float"){
        return true;
    }
    return false;
}

function isUrl(s) {
    var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/
    return regexp.test(s);
}

/*
 * Helper Form Element
*/

function createWebPage_edit(html_id, topic_name, topic_type, topic_id, current_vals, domain_used, url_read){
    // Webpage
    var propertyNames = ["uri","description"];
    var useSuggest = [false, false];
    var propertyTypes = ["/type/uri","/type/text"];
    var compoundPropertyType = '"/common/webpage"';
    var compoundProperty = "/common/topic/webpage";
    var webpages_options = {
        url_read: url_read,
        current_vals_q: '{"query":[{'+
                '"/common/topic/webpage":[{"*":null,"optional":true}],'+
                '"type":"/business/company",'+              
                '"id" : "'+topic_id+'"'+
                '}]}',              
        topicName: topic_name,
        current_vals: current_vals,
        propertyNames: propertyNames,
        propertyTypes: propertyTypes,
        topic_type: topic_type,
        topic_id: topic_id,
        compoundPropertyType: compoundPropertyType,
        compoundProperty: compoundProperty,
        useSuggest: useSuggest
    };      
    compoundElement(html_id,webpages_options, domain_used)
}

function createHeadquarters_edit(html_id, topic_name, topic_type, topic_id, current_vals, domain_used, url_read,flag){
    var propertyNames = ["street_address","citytown","state_province_region","postal_code"];
    var useSuggest = [false, true, true, true];
    var propertyTypes = ["/type/text","/location/citytown","/location/administrative_division","/location/postal_code"];
    var compoundPropertyType = '"/location/mailing_address"';
    var compoundProperty = "/business/company/headquarters";
    var hq_options = {
        url_read: url_read,
        current_vals_q: '{"query":[{'+
                '"/business/company/headquarters":[{"optional":true,'+
                    '"*":[],'+
                    '"citytown" : {"optional":true,"id" : null,"guid":null,"name" : null},'+
                    '"state_province_region":{"optional":true,"id" : null,"guid":null,"name" : null},'+
                    '"street_address":[],'+//[{"id" : null,"name" : null}],'+
                    '"postal_code":{"optional":true,"id" : null,"guid":null, "name" : null}'+
                '}],'+
                '"type":"/business/company",'+              
                '"id" : "'+topic_id+'"'+
                '}]}',                      
        topicName: topic_name,
        current_vals: current_vals,
        propertyNames: propertyNames,
        propertyTypes: propertyTypes,
        type: topic_type,
        topic_id: topic_id,
        compoundPropertyType: compoundPropertyType,
        compoundProperty: compoundProperty,
        useSuggest: useSuggest
    };  
    if(flag)
    {
        compoundElement(html_id,hq_options, domain_used,flag);
    }
    else
    {
        compoundElement(html_id,hq_options, domain_used);
    }
}
    
function createDrugPipeline(html_id, biov_domain, topic_name, topic_type, topic_id, current_vals){
        var element_structure = {
        topic1_type : '["'+biov_domain+'product","'+biov_domain+'bv_therapeutic"]',
        topic1_html_property_name : 'Therapeutic',
        button_add_string : 'Add New Therapeutic',
        parent_property : biov_domain+'science_or_technology_company/products',
        topic2 : [
            {
                type : '["'+biov_domain+'indication"]',
                topic1_property : biov_domain+'bv_therapeutic/indication_or_disease',       
                element_type : 'compound',
                button_add_string : 'Add Indication',
                elements : [
                    {
                        topic1_property : 'therapeutic',
                        topic1_property_full : biov_domain+'indication/therapeutic',
                        type : '["'+biov_domain + 'bv_therapeutic"]',
                        is_topic1 : true,
                        html_property_name : ''             
                    },
                    {
                        topic1_property : 'disease',
                        topic1_property_full : biov_domain+'indication/disease',
                        type : '["'+biov_domain + 'bv_medical_condition"]',
                        is_topic1 : false,
                        html_property_name : 'Medical Condition'
                    },
                    {
                        topic1_property : 'phase_of_development',
                        topic1_property_full : biov_domain+'indication/phase_of_development',
                        type : '["'+biov_domain + 'bv_phase_of_development"]',
                        is_topic1 : false,
                        html_property_name : 'Phase of Development'
                    }
                ]
            }
        ]
    }
    var therapeutic_pipeline_current_vals = current_vals;
    var therapeutic_pipeline_options = {
        edit_blurb : "drug pipeline",       
        topic_name: topic_name,
        current_vals: therapeutic_pipeline_current_vals,
        topic_type : topic_type,
        topic_id: topic_id,
        element_structure : element_structure
    };      
    mixedElement(html_id, therapeutic_pipeline_options);
    
}
    
    
    
    
