/**
 * contains all functi6ons for the shoutbox
 */
var Shoutbox = {
  version: 0.1,  
  currentTime: 0, 
  displayedShoutIds : [],
  mediaTypeId: 0,
  authPopup: null,  
  

  /**
  * @property settings a settings array that has to be overwritten when initializing the shoutbox
  * @type: Object
  */
  settings: {    
    updateRegularly: false,
    inlineComments: true, 
    likesEnabled: true,
    guestShoutsEnabled: false,
    currentPage: 1,
    perPage: 30,
    loggedIn: false,    
    lastModified: false,//needed if we dont want a first update after the initial call
    refreshInterval: 30000,
    limit: 1,
    chars: 140,
    type: '',
    twitterAuthorized: false,  
    labels: {
      shout_message_required : "Please enter a message",
      shout_message_guests_url_forbid: "Guests are not allowed to paste links",
      leave_shout: "Say something",
      leave_comment: "Comment on this",
      shout_message_too_long: "The message is too long"
    },
    urls: {
      list: "",
      del: "",
      detailsAjah: ""
    }    
  },
  
  /**
   * if passed into init funcs tgis object can contain overrides for certian functionality
   */
  hooks: {
  },
  
  lastShoutDate : null,  

    /**
   * @property justPosted set to true after an update so we can send different headers -> deprecated?
   */
  justPosted: false,

  /**
   * @property formOptions the options object for the ajax form submit
   * @type: Object
   */
  formOptions : {},

  /**
   * @property isBusy indicates whether a post or a delete is already being performed
   * @type Boolean
   */
  isBusy: false,
  
  /**
   * @property indicates whether an auto-update process is being performed
   * @type Boolean
   */
  isUpdating: false,

  /**
   * @property hasErrors did errors occur that prevent the form from being submitted
   * @type boolean
   *
   */
  hasErrors: false,
  
  /**
   * @property updateTimer interval object that refreshed the shoutbox periodically
   * @type Interval
   */
  updateTimer: false,
  
  updateTimerRunning: false,
  
  detailsHtml : {},
  
  initialized: false,
  
  shoutElems : [],
  
  mediaUrls:{},
  
  /**
   * a timeout for auto updating filters
   * @param {Object} params
   */
  filterTimeout: null,
  
  /**
   * counts, how many times the list has auto updated
   */
  refreshCount: 0,

  /**
   * a timeout for throttkeing event listening to textarea input
   * @param {Object} params
   */
  onKeyupTimeout: null,  
  
   
  /**
   * initialize a shoutbox
   * @param {Object} params
   */
  init: function(params, hooks){
    
    //console.info(parent.document);
    this.settings = $.extend(this.settings, params);
    
    //use passed in event functions instead of pre defined ones
    if(hooks){
      $.each(hooks, function(funcName){
        if(Shoutbox.events[funcName]){
          Shoutbox.events[funcName] = this;
        }
      });      
    }  
    
    //widget, what is thsi for? 
    if(sixGroups.settings.isWidget != null && parent) {
      var date = new Date();
      try {
        //parent.postMessage('test');
        console.log('parent', parent.location, document.location);
        parent.location.hash = '6g/'+date.getTime();
      }
      catch(e) {
      }
    }
    
    sixGroups.settings.loggedIn = params.loggedIn ? true : false;
    sixGroups.settings.loggedIn = params.isMember ? true : false;    
    
    
    //init listeners
    this.registerLiveEvents();    
    $.elementReady('shoutformContainer', Shoutbox.onFormReady);    
    $.elementReady('shoutContentContainer', Shoutbox.onContentReady);
    this.initialized = true;
    console.log('Shoutbox initilaized!', this);
  },  
 
  
  /**
   * initializes the form and attaches event listeners once it is completely loaded
   */
  onFormReady:function(){
    
    
    //jQuery form plugin options for form submit via ajax
    Shoutbox.formOptions = {      
      dataType: 'json',
      
      beforeSubmit: Shoutbox.events.onBeforePost,
      
      success: function(data){
        console.info('success!');
        Shoutbox.events.onPostSuccess(data);
      },
      
      complete: function(xhr, status, text){
        console.log('hide form');
        Shoutbox.resetForm();
               
        $('#sendForm').hide();        
        if(xhr.status != 200){//error
          alert('Sorry, an error occured');
        }        
        sixGroups.setAjaxPendingState(this.url, true);     
      },      
      
      error: function(){
        console.warn('error sending form');
      }
    };
    
    if (Shoutbox.settings.loggedIn || Shoutbox.settings.guestShoutsEnabled != false) {
      $('#shoutForm').unbind('submit').bind('submit', Shoutbox.events.onShoutFormSubmit);
      $('#shoutMessage').unbind('focus, click').bind('focus, click', Shoutbox.events.onShoutMessageFocus);
      $('#shoutMessage').unbind('keyup').bind('keyup', Shoutbox.events.onKeyUpThrottled);
    }
    else{
      $('#shoutMessage, #shoutSubmitButton').attr('disabled', 'disabled').attr('readonly', 'readonly');
    }    
    //$('#inputExternalLink').bind('change', Shoutbox.events.onExternalLinkSelected);
    
    //attach media 
    //TODO: check why these are live evetn handlers
    $('#sgMmMediaTypes a').live('click', Shoutbox.events.onAddMediaClick);
    $('#sgMmCancelAddMedia').live('click', Shoutbox.events.onCancelAddMediaClick);
    $('#sgMmCancelAddedMedia').live('click', Shoutbox.events.onCancelAddedMediaClick);
    $('.sgMmConfirmAddMedia').live('click', Shoutbox.events.onConfirmAddMediaClick);    
    
    //if the user does not have an authorized twitter account yet, bind a click handler to the checkbox to open auth in popup
    console.log('twitter', Shoutbox.settings.twitterAuthorized);
    if (Shoutbox.settings.twitterAuthorized != true) {
      $('#twitterReply').bind('click', function(){
        Shoutbox.events.onTwitterAuthFocus(this);
      });
    }
  },
  
  /**
  * initializes all event handlers, once the list is loaded
  */
  onContentReady: function(){
    
    if(Shoutbox.settings.updateRegularly !== false && 
      Shoutbox.settings.updateRegularly !== 0 
      && Shoutbox.settings.updateRegularly !== ''){
      console.log('updates for shoutbox!');
      Shoutbox.updatesOn();
    }
    else{
      console.log('no updates for shoutbox!');
    }
    
    //get the currently selected media type
    this.mediaTypeId = $(':input:checked', '#mediaFilters').val();
    
    $('#formFilter input:radio').bind('change, click', Shoutbox.events.onFilterChecked);
    $('.toggleFilters').click(
      function(){
        $('#mediaFilters').slideToggle('fast');
        $(this).toggleClass('open').find('span').toggle();
        sixGroups.Tracking.track('/shoutbox/toggleFilters');
        return false;
      }
    );        
  },
  

  
  /**
   * registers all event listeners that are supposed to happen on each element, 
   * even after the DOM is updated (e.g. new shout inserted)
   */
  registerLiveEvents: function(){
    
    $('a.deleteShout', $('#shoutList')[0]).live('click', function(){      
      Shoutbox.events.onDeleteLinkClicked(this);     
      return false;      
    });

    //like/unlike link
    if (Shoutbox.settings.likesEnabled != false) {
      $('a.like, a.unlike, a.likeLink').live('click', function(){
        Shoutbox.events.onLikeLinkClicked(this);
        return false;
      });
    }

    //"+" expand link for media e.g. videos
    $('a.mediaLink', $('#shoutList')[0]).live('click', Shoutbox.events.onExpandLinkClicked);
     
     
    //comment link (careful in SE its named commentLink)
    if(Shoutbox.settings.inlineComments == true){
      $('a.replyLink').live('click', function() {
        return Shoutbox.events.onCommentLinkClicked(this);
      });      
    }    
    
    //focus comment form
    $('.comment_box_form textarea').live('click', function() {
      Shoutbox.events.onCommentFormFocus(this);       
    });
    
    //expand comments link
    $('.expandCommentsLink', $('#shoutList')[0]).live('click', function() {      
      Shoutbox.events.onExpandCommentsLinkClicked(this);
      return false; 
    });
    
    //submit comment form
    //ie8 doesnt suppurt live('submit') event, so we have to use click
    $('.submitComment').live('click', function() {
        Shoutbox.events.onSubmitCommentForm( 
          $(this).parents('form')[0]
        );
        return false;
      });
    
    
    //for some reason doesnt work in onContentReady
    $('#getMoreShouts').live('click', function(){  
        console.log('getting more shouts from', this.href);
        sixGroups.Tracking.track('/shoutbox/moreLinkClicked');
        $('#moreLoader').show();
        $(this).hide();
        
        $.ajax({
          url: this.href,
          dataType: 'json',
          success: function(data){
            console.log('success!', data);
            Shoutbox.onFormReady();
            if(data.shouts){
              Shoutbox.addShoutsToList(
                data.shouts, 
                { removeOld : false,
                  animateIn : true,
                  animateOut : true,
                  position : 'bottom'
                }
              );
              if(data.nextPagedRoute){
                $('#getMoreShouts').attr('href', data.nextPagedRoute); 
              }
            }
            else{
              $('#moreLoader').hide();
            }
          },
          error: function(a,b,c){
            console.error(a,b,c);
            alert('Sorry, a error occurred');
          },
          complete: function(){
            $('#moreLoader').hide();
          }
        });
        return false;
      }
    );
    
    //add community bar controller to urls in shout messages (there should be a better way to do this! )
    if (sixGroups.settings.isWidget !== null){
      $('a', $('#shoutList')[0]).live('click', function(){
            //add community bar controller to links that do not contain it
            if (this.href.indexOf(sixGroups.settings.sgDomain) > -1 //contains sgdomain
              && this.href.indexOf('community_bar.php') == -1 //does not contain controller             
              && this.className.indexOf('external') == -1 //is not external
              && this.rel.indexOf('external') == -1)
            {
              var newHref ='/community_bar.php' + this.href.substr((this.href.indexOf(sixGroups.settings.sgDomain) + sixGroups.settings.sgDomain.length));
              //console.log('changing href', this.href , newHref);
              this.href = newHref; 
           }
         });
    }
  },
  
  
  /**
   * is supposed to contain all event handling function from Shoutbox
   */
  events: {
    
    /**
     * called, when once of the links to add media is clicked
     */
    onAddMediaClick: function(){
      
      $('#sgMmMediaTypes').hide();      
      $('#sgMmAddMediaContainer').show();
      $('#shoutSubmitButton').addClass('disabled').attr('disabled', 'disabled');
      $('.urlInput', '#shoutForm').val('');
      $('#sgMmFileInput', '#shoutForm').val('');
      
      
      //$('#shoutSubmitButton').addClass('disabled').attr('disabled', 'disabled');
        
      var activeLayer = $('.sgMmMediaLayer:visible');
      var newActiveLayer =  $('#'+this.rev);
      var mediaType = this.rel;
        
      //hide the currently active layer and show the new one     
      $(activeLayer).hide();
      $(newActiveLayer).show();
        
      //clear all currently added media
        
      //show hide url /file inputs
      if(this.rev == 'sgMmPhoto'){
        //console.info('pick photo!');
        
        //switch photo tabs
        $('#sgMmAddPhotoByUrl')
          .unbind('click', Shoutbox.events.onPhotoAddByUrlSelected)
          .click(Shoutbox.events.onPhotoAddByUrlSelected);
              
        $('#sgMmAddPhotoByUpload')
          .unbind('click', Shoutbox.events.onPhotoAddByUploadSelected)
          .click(Shoutbox.events.onPhotoAddByUploadSelected);        
      }
      else{
        $('#sgMmUrlInput').empty();
        $('#sgMmFileInput').hide().attr('disabled', 'disabled');
        $('#urlFieldContainer').show();        
      }               
        
      //set "tab" state to active
      $('#sgMmMediaTypes span').removeClass('active');
      $(this).parent('span').addClass('active');          
        //hide all tab contents and show active tab
      sixGroups.Tracking.track('shoutbox/changeMediatypeAddMedia_'+mediaType);        
      return false;      
    },
    
    /**
     * cancels an addMedia dialogue
     */
    onCancelAddMediaClick: function(){      
      //hide the media add form and reactivate the send button
      $('#sgMmMediaTypes').show();
      $('#sgMmToolbarMenu').show();
      $('#shoutSubmitButton').show().attr('disabled', '').removeClass('disabled');
      $('#sgMmAddMediaContainer').hide();      
      Shoutbox.checkFormState();
      //remove all media curretnly attached
      return false;
    },
    
    /**
     * removes an already added attachment
     */
    onCancelAddedMediaClick: function(){
      //console.log('hide media box');
      //hide the media add form and reacrivate the send button
      $('#sgMmAddMediaContainer', '#shoutForm').hide();
      $('#sgMmMediaTypes, #sgMmToolbarMenu', '#shoutForm').show();      
      $('#shoutSubmitButton', '#shoutForm').show().attr('disabled', '').removeClass('disabled');
      $('#sgMmMediaPreview', '#shoutForm').empty();
      $('#sgMmMedia', '#shoutForm').hide();
      Shoutbox.checkFormState();
      $('input.hiddenMediaInfo', '#shoutForm').val('');       
      //remove all media curretnly attached
      return false;
    },
    
    
    /**
     * once a media is selected, the needed data is requested and added to the hidden fields
     */
    onConfirmAddMediaClick: function(){
      //clear up all old values
      $('input.hiddenMediaInfo', '#shoutForm').val('');      
      
      //file upload
      if ($('#sgMmFileInput').val().length > 0) {
        //console.log('upload image', $('#sgMmFileInput').val());
        $('#sgMmFileInput').clone().attr('id', 'temporaryPhotoUpload').appendTo($('#sgMmUploadPhotoForm'));
        $('#sgMmUploadPhotoForm').ajaxSubmit({
          dataType: 'json',  
          type: 'POST',   
          beforeSubmit: function(){
            $('#sgMmMedia').show();   
            $('#sgMmMediaPreview').html('<div class="ajaxLoader" id="uploadingStreamImageStatus">loading</div>').show();
            $('#sgMmAddMediaContainer').hide();
            $('#sgMmFileInput').val('');       
          },
          success: function(data){
            if(data){
              if(data.status == "200"){
                Shoutbox.events.onMediaDataReceived(data);
                $('#inputExternalLink').val(data.external_link);
                $('#temporaryPhotoUpload', '#sgMmUploadPhotoForm').remove();                
              }
              else{
                var alertMsg = 'Sorry, errors occurred: ';
                for(var i = 0; i < data.errors.length; i++){
                  alertMsg += data.errors[i];
                }
                alert(alertMsg);              
                $('#sgMmAddMediaContainer').hide();
              }
            }
            else{
              console.warn('no data received');
              $('#sgMmAddMediaContainer').hide();
            }
          },
          error: function(){alert('Sorry, an error occurred!');} //cannot happen, as this is no "true" ajax
        });             
        return false;
      }
      
      
      //url input --> get remote info
      else {   
        try {          
          var url = $('input.urlInput', $('.sgMmMediaLayer:visible')).val();
          var title = ''; //$('#sgMmTitleInput').val();
          var content = $('#shoutMessage').val();
          if (title === '') {
            title = url;
          }
                    
          if (url !== '') {            
            //create a loader and get remote mediadata
            $('#sgMmMedia').show();   
            $('#sgMmMediaPreview').html('<div class="ajaxLoader">loading</div>').show();
            
            //call the media func
            Shoutbox.getMediaInfo(url, Shoutbox.events.onMediaDataReceived);
                        
                  
            //remove default message
            var regexp = new RegExp(Shoutbox.settings.labels.leave_shout);
            var res = regexp.exec(content);            
            
            //no text has been added yet, the default message is replaced with the url TODO: replace with a default post link
            if (res) {              
              console.info(res, Shoutbox.settings.labels.leave_shout, Shoutbox.settings.labels.leave_comment);
              content = content.replace(res[0], Shoutbox.settings.labels.leave_comment);
              content = content.replace('\?', '');
               $('#shoutMessage').val(content);               
            }
            
            //
            else if($('#shoutMessage').val() === ''){
              $('#shoutMessage').val(Shoutbox.settings.labels.leave_comment);
              
              $('#shoutMessage').focus(
                function(){
                  if($(this).val() == Shoutbox.settings.labels.leave_comment){
                    $(this).val('');
                  }
                }
              );
            }
            
            //fill hidden fields
            $('#inputExternalLink').val(url);
            
            //this is for url recognition in textarea... might be deprecated soon
            $('#shoutMessage').unbind('keyup'); //remove auto updating of media, as we have already added one manually              
            if (title.length > 0) {
              $('#inputShoutTitle').val(title);
            }
            else {
              $('#inputShoutTitle').val('');
            }
          }
          else{
            $('#sgMmMediaTypes').show();
          }
          $('#sgMmToolbarMenu').show();
          $('#sgMmAddMediaContainer').hide();
        }      
        catch (e) {         
          console.error('could not ge media data', e);          
        }
        return false;
      }
    },
    
      /**
      * called, once media data is available for a certian url
      * @param {Object} mediaData received media data, note: column names are used, so underscore instead of camel case! external_link, NOT externalLink
      * 
      */
     onMediaDataReceived: function(mediaData){
       //var mediaData = mData || false;    
       if(mediaData){
         if(mediaData.status != 200){
           console.warn('something went wrong', mediaData);
         }
         else{
           $('#sgMmMedia').show();
           $('#sgMmMediaPreview').show().empty();
           var content = $('<div></div>');
           //console.log('remote data received, adding media preview', mediaData);
           var title = mediaData.title  || mediaData.external_link;
           $('#inputShoutTitle').val(title);     
           $('#inputMediaType').val(mediaData.mediatype_id);
           $('#inputServiceId').val(mediaData.service_id);
           
           if($('#shoutMessage').val() === '' || $('#shoutMessage').val() == Shoutbox.settings.labels.leave_shout){
             $('#shoutMessage').val(Shoutbox.settings.labels.leave_comment); 
           } 
            
           $(content).append('<p><a href="'+mediaData.external_link+'" target="_blank">'+title+'</a></p>');
           
           if(mediaData.description){
             $(content).append('<p>'+mediaData.description+'</p>');
             $('#inputDescription').val(mediaData.description);
           }
           
           if(mediaData.images){
             //console.log('mdata images', mediaData.images);
             $.each(mediaData.images, function(){
               $(content).append('<img src="'+this+'" style="display:none;"/>');           
             });
             
             //set thumbnail to first image
             $(content).find('img:first').show();       
             $('#inputThumbnailUrl').val(mediaData.images[0]);
             if(mediaData.images.length > 1){
              //TODO: add links to toggle through the images  
             }         
           }
           
           $('#sgMmMediaPreview').html(content);       
         }       
         $('#shoutSubmitButton').attr('disabled', '').removeClass('disabled');
       }
       else{
         console.warn('no data received');
       }
     },
       /**
       * shows the add photo by url view
       */
      onPhotoAddByUrlSelected : function(){
        $(this).addClass('current');
        $('#sgMmAddPhotoByUpload').removeClass('current');
        $('#sgMmPhotoAdd').show();
        $('#sgMmPhotoUpload').hide();
        $('#sgMmFileInput').hide().attr('disabled', 'disabled');
        $('#sgMmFileInput').val('');            
        return false; 
      },
      
      /**
       * shows the add photo by upload view
       */
      onPhotoAddByUploadSelected : function(){
        $(this).addClass('current');
        $('#sgMmAddPhotoByUrl').removeClass('current');
        $('#sgMmPhotoAdd').hide();
        $('#sgMmPhotoUpload').show();
        $('#sgMmFileInput').show().attr('disabled', '');
        $('input.urlInput', $('.sgMmMediaLayer:visible')).val();
        return false;
      },
      
     
      
      /**
      * triggers a throttleded submit if filters are changed
      */
      onFilterChecked:function(){
        $(this).parent('li').addClass("active");
        var mediaTypeId = $(':input:checked', '#mediaFilters').val();
        //media type has changed, reset list
        if(Shoutbox.mediaTypeId != mediaTypeId){
          $('#mediaFilters li').removeClass('active');
          clearTimeout(Shoutbox.filterTimeout);
          this.filterTimeout = setTimeout(Shoutbox.submitFilters, 300);
        }
        
      },
     
     /**
      * receives new shout data after a post
      * @param {Object} data
      */ 
     onPostSuccess: function(data){ 
     console.info('success', data);   
      if(data){
        //Shoutbox.refreshCount = 0;
        console.info('post success', data);
        if($('#shoutList').length < 1){//create list
          $('#noShoutsYet').hide();//remove an eventual container if there where no shouts beforehand        
          $('<ol id="shoutList" class="shouts"></ol>').appendTo($('#shoutListContainer'));
        }
        
        //add entries to list
        Shoutbox.addShoutsToList(data.shouts);
        Shoutbox.animateShout(':first');
        sixGroups.refresh(null, true);  
        
        
        if(sixGroups.settings.isWidget !== null){
          //TODO: notify parent window (ff3, safari3, ie8)
        }
        
        $('#shoutMessage').focus();
        var showStatus = false;
        
        //show twitter message    
        if(data.twitter && data.twitter.message) {     
          $('#twitterStatus').addClass('error');        
          try {
            if (data.twitter.info.http_code == 200) {
              $('#twitterStatus').removeClass('error').addClass('ajaxSuccess');
            }
          }
          catch(e){}
          $('#twitterStatus').text(data.twitter.message).show();
          showStatus = true; 
        }
        
        if(data.facebook && data.facebook.message) {      
          $('#fbStatus').addClass('error');        
          try {
            if (data.facebook.info.http_code == 200) {
              $('#fbStatus').removeClass('error').addClass('ajaxSuccess');
            }
          }
          catch(e){}
          $('#fbStatus').text(data.facebook.message); 
          showStatus = true;
        }
        
        if(showStatus == true){
          $('#sendStatus').show();
        }        
        
        
        //get lastModified, so we dont re-request those shouts
        if(data.lastModified){
          Shoutbox.settings.lastModified = data.lastModified;
        }     
        
        //turn updates on again
        if(Shoutbox.settings.updateRegularly !== false && Shoutbox.settings.updateRegularly !== 0){
          Shoutbox.updatesOn();
        }    
        
        //tracking
        try {
          sixGroups.Tracking.track('/shoutbox/shouted');
        }        
        catch (e){
          console.warn(e);
        }
      }
      else{
        alert('We are sorry, an error occured: no data was returned');
      }
      Shoutbox.resetForm();            
    },
    
    /** 
     * performs validation before submit of form
     */
    onBeforePost: function(){      
      console.log('before post!');
        Shoutbox.updatesOff();        
        var valid = Shoutbox.validate();
        if (valid === false) { 
        console.warn('is invalid!');       
          return false;
        }
        
        //all good -> submit form and retrieve messages
        else {
          console.log('all good');
          
          //delete default comment
          if($('#shoutMessage').val() == Shoutbox.settings.labels.leave_comment){
            $('#shoutMessage').val('');
          }
          
          
          //if mediafilter != all or messages, set filters to "all"
          if($('#mediaFilters').length > 0){
            var mediaTypeId = $(':input:checked', '#mediaFilters').val();
            if(mediaTypeId != 0){
              $('input:radio', '#mediaFilters').unbind('change, click', Shoutbox.events.onFilterChecked);
              $('input:radio:first', '#mediaFilters').attr('checked', 'checked');
              $('input:radio', '#mediaFilters').bind('change, click', Shoutbox.events.onFilterChecked);
              
              try {
                this.data.mediaType = 0;
              }
              catch(e){
                console.warn(e);
              }          
              //console.log('adding data', this.data);      
            }          
          }
             
          sixGroups.setAjaxPendingState(this.url);
          $('#sendForm').show();          
          $('#shoutMessage').val(Shoutbox.settings.labels.leave_shout);          
          $('#sgMmMediaPreview').html('');
          $('#sgMmMediaPreviewLabel').hide();
          $('#sendStatus').find('div').empty().end().hide();
        }
        return true;
    },
    
      
      /**
     * handle form submisison via ajax
     * @param {Object} event
     */
    onShoutFormSubmit: function(event){  
      Shoutbox.validate();
      if(Shoutbox.hasErrors == false){
        console.log('submit', Shoutbox.formOptions);
        $('#shoutForm').ajaxSubmit(Shoutbox.formOptions);
        //TODO remove?
        $('#chars_left span').text(Shoutbox.settings.chars);
      }
      else{
        console.warn('errors exist');
      }    
      return false;
    },
    
    /**
     * focus on input form
     * @param {Object} event
     */
    onShoutMessageFocus: function(event){
      if($('#shoutMessage').hasClass('livestream')){
        $('#shoutMessage').removeClass('livestream').addClass('livestreamLarge');
        $('#sgMmToolbar').show();      
      }
      
      if($('#shoutMessage').val()== Shoutbox.settings.labels.leave_shout || $('#shoutMessage').val() == Shoutbox.settings.labels.leave_comment){
        $('#shoutMessage').val('');     
      }
    },
    
    
    /**
    * delete a post and reload the list
    */
    onDeleteLinkClicked: function(deleteLink) {
        var listItem = $(deleteLink).parents('li')[0];      
        
        $(deleteLink).removeClass('icon, deleteShout');
        $(deleteLink).addClass('ajaxLoader pl20');
  
        $.ajax({
          url: deleteLink.href,
          dataType: "json", 
          beforeSend: function(){
            sixGroups.setAjaxPendingState(this.url);
          },      
          success: function(data){
            $(listItem).fadeOut();                     
          },
          complete: function(){
            sixGroups.Tracking.track('/shoutbox/shoutDeleted');
            sixGroups.setAjaxPendingState(this.url, true); 
          },
          error: function(){
            
          }        
        });
        return false;
    },
    
    
    /**
     * shows an inline comment form
     * @param DOM-Node elem the clicked element
     */
    onCommentLinkClicked: function(elem){
      if(Shoutbox.settings.loggedIn || Shoutbox.settings.guestShoutsEnabled != false) {        
        var commentsBox = $('#comments_box_'+elem.id);
        $(commentsBox).show();
        var textarea = $(commentsBox).find('textarea');
        $(textarea).val('').focus();
        $(textarea).css('height', '40px');
        $(textarea).css('color', '#444444');
        $(textarea).parents('.comment_box_form').find('.smallButton').show();
      }
      return false;
    },
    
    
    onCommentFormFocus: function(elem){
      Shoutbox.updatesOff();   
      if(Shoutbox.settings.loggedIn || Shoutbox.settings.guestShoutsEnabled != false) {        
        if($(elem).val() == Shoutbox.settings.labels.leave_comment) {
          $(elem).val('').focus();
          $(elem).css('height', '40px');
          $(elem).css('color', '#444444');
          $(elem).parents('.comment_box_form').find('button').show();
        }
      }
      else {
        console.log('please log in!');
      }
      
      $(elem).unbind('blur').blur(
        function(){
          if(Shoutbox.settings.updateRegularly !== false){
            Shoutbox.updatesOn();            
          }          
        }
      );
    },
   
    /**
     * likes
     */
    onLikeLinkClicked: function(elem){
      console.log('like link clicked!', elem);
      $.ajax({
          url: elem.href,
          dataType: "json",
          
          beforeSend: function(){
            $(elem).removeClass('smallHeartGray').addClass('icon ajaxLoader');
            sixGroups.setAjaxPendingState(this.url);
          },
          
          success: function(data){
            var listTarget =  $(elem).parents('.streamContent').find('.like_box');
            console.info('like call', data, elem, listTarget);
            //create a list below the entry ('you like this');
            
            //on sg, we have a list of likes
            if(listTarget){
              $(listTarget).replaceWith(data.likeListHtml);  
            }
            //on se we replace the previous link with the content
            else{
              $(elem).parent('span.likeArea').replaceWith(data.likeAreaHtml);
            }
            
            //TODO: find like area in parent on unlike, it's not replaced atm!
            
            //this is the actual link            
            
            //on sg this is replaced with an empty area after like, on se this is replaced with a link containing the "lecker" count
            $(elem).parent('span.likeArea').replaceWith(data.likeAreaHtml);
            $(elem).removeClass('ajaxLoader').addClass('smallHeartGray');
            var mode = 'unlike';
            if($(elem).hasClass('like')){
              mode = 'like'; 
            }
            sixGroups.Tracking.track('/shoutbox/'+mode+'/'+data.shoutId);
          },
          
          
          complete: function(){          
             sixGroups.setAjaxPendingState(this.url, true); 
           },
          error: function(){
            
          } 
        });
     return false;
   },
   
   
        
    /**
     * show/hide detail view
     * @param {Object} event
     */
    onExpandLinkClicked: function(event){
        var elem = this;
        var listElem = $(this).parents('li')[0];
        var detailElem = $('.serviceDetails', listElem)[0];//the whole detail block
        var detailContentElem = $('.serviceContent', detailElem)[0]; //only the part that the new content is loaded to
        var shoutId = this.rev;
        
        if(detailElem !== null){
          if($(detailElem).css('display') == 'none'){
            Shoutbox.updatesOff();
          }
          else{
            Shoutbox.updatesOn();
          }       
         
                  
          $(detailElem).slideToggle('fast',
            function(){
              try {
                Shoutbox.turnOffUpdatesIfDetailsOpen();                        
                $(elem).toggleClass('minusIcon');      
              } 
              catch (e) {
                console.error(e);
              }
              
              //content area faded in
              if($(detailElem).css('display') !== 'none'){
                sixGroups.Tracking.track('/shoutbox/openDetails/'+shoutId);
                
                //content stilll has to be loaded
                if(
                //$(detailContentElem).find('.ajaxLoader').length > 0
                typeof Shoutbox.detailsHtml[shoutId] == 'undefined'
                ){
                  var contentUrl = Shoutbox.settings.urls.detailsAjah+'/'+shoutId+'/';
                  $.ajax({
                    url: contentUrl,
                    success: function(data){
                      Shoutbox.detailsHtml[shoutId] = data;
                      $(detailContentElem).empty().prepend(data).show();                    
                    }
                  });
                }
                
                //content is already loaded
                else{    
                  //console.log('content already loaded', Shoutbox.detailsHtml[shoutId]); 
                  $(detailContentElem).empty().html(Shoutbox.detailsHtml[shoutId]);
                }
              }
              
              //content area faded out
              else{
                //move in, clear inner html to prevent continued loading
                $(detailContentElem).empty();
                sixGroups.Tracking.track('/shoutbox/closeDetails/'+shoutId);              
              }
            });
      }
      return false;    
    },
    
    
    onKeyUpThrottled: function(e){
      //TODO: if text contains a url, detect mediasixGroups.mediaManager.detectMedia($('#shoutMessage').val());
    },
    
    onKeyUp: function(e){
      clearTimeout(Shoutbox.onKeyupTimeout);   
      Shoutbox.onKeyupTimeout = setTimeout(Shoutbox.events.onKeyUpThrottled, 50);    
      var count = $('#shoutMessage').val().length;
      if(count <= Shoutbox.settings.chars) {
        $('#chars_left span').text(Shoutbox.settings.chars - count);
      }
      if(count > 120) {
        $('#chars_left span').css('color','#F20278');
      }
      else {
        $('#chars_left span').css('color','#999');
      }
       
    },
    
    /**
     * when a url is selected via the addmedia buttons, or when a url that is auto detected is found, this function triggers an ajax request to get the specific data for that url
     */
    onExternalLinkSelected: function(){
      //console.log('external link selected!', this.value);
      Shoutbox.getMediaInfo(this.value, function(data){
        //console.log('media data received!', data);
      });
    },
    
    /**
     *  appends a list of comments for a shout inside the stream
     */
    onExpandCommentsLinkClicked: function(linkElement) {
      var liElement = $(linkElement).parent();
      
      $.ajax({
          url: linkElement.href,
          dataType: "json", 
          beforeSend: function(){
            sixGroups.setAjaxPendingState(linkElement.url);
            $(liElement).removeClass('icon smallHeartGray').addClass('ajaxLoader');
          },      
          success: function(data){
            if(data.shouts){
              var shouts = data.shouts;  
              var commentList = $(liElement).parent();
              $('li:first, li:last', commentList).remove();
              
              for(var i = shouts.length; i>=0;  i--){
                try{
                  if(shouts[i]){
                    $(commentList).append(shouts[i].html);                                      
                  }
                }
                catch(e){
                  console.warn(e, i);
                }
              }
              
            }
          },
          complete: function(){
            $(liElement).hide();
            sixGroups.Tracking.track('/shoutbox/expandComments');
            sixGroups.setAjaxPendingState(linkElement.url, true); 
          },
          error: function(){
            
          }        
      });  
    },
    
    /**
     *  submits the comment form an appends shout to list
     */
    onSubmitCommentForm: function(formElement) {
      if (Shoutbox.settings.loggedIn || Shoutbox.settings.guestShoutsEnabled != false) {
        var formOptions = {
          dataType: 'json',
          
          
          beforeSubmit: function(formData, jqForm, options){
            Shoutbox.isUpdating = true;//set update satte to true to prevent that refrehs deletes comment
            var textarea = $(formElement).find('.comment_textarea');
            var text = sixGroups.stripTags($(textarea).val());
            //console.log('submit comment', $(formElement).attr('action'), sixGroups.isPending($(formElement).attr('action')));
            
            if (text === '' || text == Shoutbox.settings.labels.leave_comment || sixGroups.isPending($(formElement).attr('action'))) {
              return false;
            }
            else {
              sixGroups.setAjaxPendingState($(formElement).attr('action'), false);
              $(textarea).addClass('ajaxLoader');
              return true;
            }
          },
          
          success: function(data){
            if (data.shouts) {
              var shouts = data.shouts;
              var commentList = $(formElement).prevAll('.comments_list');
              
              for (var i = shouts.length; i >= 0; i--) {
                try {
                  if (shouts[i]) {
                    if ($('#commentItem_' + shouts[i].id, $(commentList)[0]).length < 1) {
                      $(commentList).append(shouts[i].html);
                    }
                    else {
                    //console.log('shout is already attached');
                    }
                  }
                } 
                catch (e) {
                  console.warn(e, i);
                }
              }
              
              //reload bar on success 
              if (sixGroups.settings.isWidget === null) {
                sixGroups.refresh(null, true);
              }
              else {//TODO: notify parent window (ff3, safari3, ie8)
              }              
              
              //count up comments count
              if(data.num_comments){
                $('.commentCount').text('('+data.num_comments+')');
              }
              
              
              //remove loader ani and set textarea to default
              $(formElement).find('textarea').val(Shoutbox.settings.labels.leave_comment).css('color', '#777777').css('height', '16px').removeClass('ajaxLoader');
              
              //TODO: TEST!
              //tracking 
              try {
                sixGroups.Tracking.track('/shoutbox/response/' + $(formElement).find('.shoutData_parent_id').val());
                
              } 
              catch (e2) {
                console.warn(e2);
              }
            }
          },
          
          complete: function(xhr, status, text){
            Shoutbox.isUpdating = false;
            if (xhr.status != 200) {//error
              console.error('Sorry, an error occured', xhr, status, text);
              console.error('Sorry, an error occured');
            }
            sixGroups.setAjaxPendingState(this.url, true);
          },
          
          error: function(){
            console.warn('error sending form');
          }
        };
        
        $(formElement).ajaxSubmit(formOptions);
      }
      return false;    
    },     
    
    
    onTwitterAuthFocus: function(elem){   
    console.log('twitter auth', $(elem).attr('checked'));
      //if user is not authorized, open popup, otherwise dpnt do stuff
      if($(elem).attr('checked')){
        Shoutbox.authPopup = sixGroups.popup(
          $(elem).attr('data-url'), 
          'Authentication', 
          {width: 800, height: 500} 
        );
        sixGroups.Tracking.track('/shoutbox/twitterAuthFocus');
      }
      //console.log('twitter auth focus', elem, $(elem).attr('data-url'));      
      //var message = $('#shoutMessage').val();      
      /* if(message == '' || message == Shoutbox.settings.labels.leave_shout){
        message = '@<?php echo $replyTo ?> ';
      }
      else {
        var atName = '@TODO: add name';
        var atNameLength = atName.length;
        var prefix = message.substring(0, atNameLength);
  
        if(prefix == atName) {
          message = message.slice(atNameLength+1);
        }  
        message = atName + ' ' + message;
      }  
      $('#shoutMessage').val(message);
      $('#shoutMessage').focus(); */      
    },
    
    
    
    /**
     * called from a popup, once oauth is complete
     * @param {Object} accountData
     */
    onTwitterAuthComplete: function(response){
      if(response.status == 200){
        var account = response.account;
        console.log('auth complete', response);
        $('#twitterReply').attr('disabled', false)
        .unbind('focus')//remove popup func
        .attr('checked', true);
        $('#twitterUsername').text(' ('+account.username+')');
        sixGroups.Tracking.track('/shoutbox/TwitterAuthComplete');
        Shoutbox.authPopup.close();
        $('#twitterAuthContainer').animate(
          {'backgroundColor': '#E20177'}, 500,
          function(){
            $('#twitterAuthContainer').animate({'backgroundColor': '#efefef'}, 500);             
          }
        );
      }
    }
    
  },//end shout events
  
  


  /**
   * submits the filter form
   */
  submitFilters: function(){
    //media type has changed, reset list
    sixGroups.Tracking.track('/shoutbox/changeFilters');
    $('#streamLoader').show();    
    Shoutbox.update({
      forceUpdate: true,
      replace: true
    });
  },
  
   
  
  
  ajaxifyPager: function(){
    /* var onBeforeSubmit = function(){
      window.scrollTo(0,0);      
    };
    var onSuccess = function(){};
    
    sixGroups.ajaxifyPager('#shoutBoxContainer',
      {'onBeforeSubmit': onBeforeSubmit,
        'onSuccess' : onSuccess
      }
    );*/
  },
  
  
  

  /**
  * update the shoutbox content in a predefined interval
  */
  periodicUpdater : function(){
    //should be 1, 1, false, 0
    /*console.info('periodic update',
      Shoutbox.settings.currentPage,
      Shoutbox.settings.updateRegularly,
      Shoutbox.isUpdating, 
      sixGroups.pendingUpdates.length 
    );*/
    
    if(Shoutbox.settings.currentPage == 1 
      && Shoutbox.settings.updateRegularly !== false
      && Shoutbox.isUpdating === false
      && sixGroups.pendingUpdates.length < 1
      ){
      try{
        Shoutbox.update();
      }
      catch(e){}
    }
  },

  
  animateShout: function(listIdentifier){
    var bgColor = '#FFFFFF';    
    $('#shoutList li'+listIdentifier).animate(
      {'backgroundColor': '#E20177'},
      500,
      function(){
        $('#shoutList li'+listIdentifier).animate({
          'backgroundColor': bgColor
        }, 500);             
      }
    );
  },

  animateBackground: function(){
    var bgColor = '#F8FAFB';
    //badd, this should be sutomizable via settings, not depending on astring
    if(Shoutbox.settings.type == 'communityHome') {
      bgColor = '#FFFFFF';
    }
    $('#shoutList').animate(
      {'backgroundColor': '#E20177'},
      500,
      function(){
        $('#shoutList').animate({
          'backgroundColor': bgColor
        }, 500);             
      }
    );
  },
  
  /**
  * validate the shoutbox input
  *
  */
  validate: function(type){
    var errors = [];
    var text = $('#shoutMessage').val();        
    text = sixGroups.stripTags(text);
    //console.log('current text', text);
    
    //if still posting, show wait message?


    //if text is = default text or empty
    if($('#inputMediaType').val() == '' && (text == '' || text == this.settings.labels.leave_shout )){      
      errors.push(this.settings.labels.shout_message_required);      
    }
    
    //if not logged in and trying to post urls
    if(sixGroups.settings.loggedIn !== true){
      if(text.indexOf("http://") != -1 || text.indexOf("www.") != -1){
        errors.push(this.settings.labels.shout_message_guests_url_forbid);        
      }
    }   
    
    else if(text.length > 140){
      //errors.push(this.settings.labels.shout_message_too_long);
    }

    if(errors.length > 0){
      $('#shoutformErrors').css('display','block');
      $('#shoutformErrors').text(errors.join('<br/>'));      
      $('#shoutMessage').focus();
      Shoutbox.hasErrors = true;
      return false;
    }
    else{
      Shoutbox.hasErrors = false;
      $('#shoutformErrors').empty();
      $('#shoutformErrors').hide();
      $('#sgMmAddMediaContainer').hide();
       $('#sgMmMedia').hide();        
      return true;
    }
  },
  
  /**
   * retrieves additional media data for a url
   * @param {Object} url
   * @param {Function} callback a function taking one optional argument (data). If not data is passed, the funciton can use this to display an initial state or a loading animation
   */
  getMediaInfo: function(url, callback){
      //console.log('getting media info', url, callback, Shoutbox);
      
      if(typeof Shoutbox.mediaUrls[url] == 'undefined'){        
        //console.log('getting remote data for', Shoutbox.mediaUrls[url], url, Shoutbox.mediaUrls);
        var remoteUrl = '/resource/getRemoteMediaInfoJson/?mediaUrl='+encodeURIComponent(url);
        
        $.ajax({
          url: remoteUrl,        
          dataType: 'json',
          beforeSubmit: function(){
            //console.log('beforeSubmit', url, this.url);
            Shoutbox.mediaUrls[url] = 'loading';
          },
          success: function(data){
            if(data){
              //console.log('success', url, this.url, data);
              Shoutbox.mediaUrls[url] = data;
              callback(data);              
            }
            else{
              console.warn('problenms getting media data');
            }
          },
          complete: function(){
            console.log('complete', url);
          }
        });
        
        //call the callback function without data (this will only create a loader)
        callback();
      
      }
      //still loading, dont load again, just keep the loader
      else if(Shoutbox.mediaUrls[url] == 'loading'){
        callback();              
      }
      else {
        callback(Shoutbox.mediaUrls[url]);        
      }
      return false;
   }, 
   



  /**
   * updates the contents of the current stream, used for auto refreshing and also when the more link is clicked
   */
  update: function(params){
    params = params || {};
    var postData = {};    
    
    /**
     * default settings
     */
    var options = {
      forceUpdate : false,
      
      /**
       * where to insert
       */  
      position : 'top',
      
      /**
       * if this is set to true, new data replaces contents of the list instead of being appended
       */
      replace: false,
      onSuccess: function(data) {},
      onComplete: function(xhr, message) {},
      onError: function(xhr, message) {}
    };
    
    options = $.extend(options, params);       
   
    
    //add post data
    if(params.data){
      postData = $.extend(postData, params.data);
    }
    
    //if media type id is not set to all, or it has changed since last update, get new contents    
    if ($('#mediaFilters').length > 0) {
       var mediaTypeId = $(':input:checked', '#formFilter').val();
       if (mediaTypeId != Shoutbox.mediaTypeId) {
         console.log('media filters have changed!', mediaTypeId, Shoutbox.mediaTypeId);
         postData.mediaType = mediaTypeId;
         postData.forceUpdate = true;
         options.replace = true;
         Shoutbox.mediaTypeId = mediaTypeId;
       //TODO: we could set a lastmodified here as well 
      }
    }
        
    var loadIfModified = (postData.forceUpdate) ? false : true;
    
    //IE caches everything :(
    if($.browser.msie){
      loadIfModified = false;
    }  
    console.log('doing update with', options, postData);  
     

    
    //parameters
    var ajaxParams =  {
      type: 'GET',
      url: Shoutbox.settings.urls.list,      
      ifModified : loadIfModified,
      data: postData,
      dataType: 'json',
            
      success: function(data){       
        try{
          console.info('received new data', data);
          /*if (options.replace === true) {
            $('#shoutList').empty();
          }*/
            
          if(data){  
            if(data.page){
              Shoutbox.settings.currentPage = data.page;
            }            
           
            if(data.shouts && data.shouts.length > 0){
              //if IE, the lsat-modified directive doesnt work :( 
              Shoutbox.addShoutsToList(data.shouts, options);
            }
            /*else{              
              if(options.replace === true){             
                $('#noShoutsYet').show();            
              }
            } */             
          }     
        }
        catch(e){
          throw('error on shout insert: '+ e);
        }  
        
        
       try{
         options.onSuccess(data);         
       }catch(e){
         console.warn(e);
       }        
      },      

      complete: function(xhr, statusText){
        //alert('complete!');     
        Shoutbox.isUpdating = false;
        $('#streamLoader').fadeOut();
        try{
         options.onComplete(xhr, statusText);         
       }catch(e){
         console.warn(e);
       }
      },      
      
      beforeSend: function(xhr){        
        Shoutbox.isUpdating = true;
        //before first update, we set the if-modified-since header to the shoutbox load date     
        if(loadIfModified && Shoutbox.settings.lastModified !== false){
          xhr.setRequestHeader("If-Modified-Since", Shoutbox.settings.lastModified);
          Shoutbox.settings.lastModified = false;          
        }   
        Shoutbox.refreshCount++;
      },
      
      error: function(xhr, message){
        if(xhr.statusText != 'OK'){
          console.warn('Sorry! Something went wrong', message);
        }
        try{
         options.onError(xhr, message);         
       }catch(e){
         console.warn(e);
       }
      }
    };    
    console.info(ajaxParams);
    $.ajax(ajaxParams);
  },
  
  /**
   * add new shouts to the list and animate them
   * @param {Object} shouts
   * @param {Object} params
   */
  addShoutsToList:function(shouts, params){
    $('#noShoutsYet').hide();
    
    var options = {
      removeOld : false,
      animateIn : true,
      animateOut : true,
      position : 'top'      
    };
    
    var numAppended = 0;
    var numPrepended = 0;
    
    var shout = null;
    
    options = $.extend(options, params);
    console.info('adding shouts to list', options, shouts);
    
    //autoupdate
    if (options.position === 'top'){
      for(var i = (shouts.length-1); i>=0;  i--){
        try{
          if( $('#streamItem_'+ shouts[i].id, $('#shoutList')[0]).length < 1){
            $('#shoutList').prepend(shouts[i].html);
            numPrepended++;
          }
        }
        catch(e){
          console.warn(e, i);
        }
      }
    }
    
    //more link
    else{
      for(var i = 0; i < shouts.length; i++){
        try{
          if( $('#streamItem_'+ shouts[i].id, $('#shoutList')[0]).length < 1){
              $('#shoutList').append(shouts[i].html);          
          }
        }
        catch(e){
          console.warn(e, i);
        }
      }
      //hide more link if last query delivered less than 30 shouts
     console.log('length/appended', shouts.length, numAppended, Shoutbox.settings.perPage);
     if(shouts.length < Shoutbox.settings.perPage){
       $('#getMoreShouts').hide();
     }
     else{
       $('#getMoreShouts').show();
     }
    }
  },


  updatesOff: function(){
    //console.log('updates off!');
    Shoutbox.updateTimerRunning = false;
    clearInterval(Shoutbox.updateTimer);
  },

  updatesOn: function(){            
    try{     
      console.log('periodic shoutbox refresh at', Shoutbox.settings.refreshInterval);
      Shoutbox.updateTimerRunning = true;
      clearInterval(Shoutbox.updateTimer);
      Shoutbox.updateTimer = setInterval(
        Shoutbox.periodicUpdater, 
        Shoutbox.settings.refreshInterval
      );      
    }
    catch(e){
      console.error(e);
    }
  },

  //if any of the views inside the stream are open, we have to stop the stream
  turnOffUpdatesIfDetailsOpen : function(){
    var numVisibleDetailElems = $('#shoutList .serviceDetails:visible').length;
    if(numVisibleDetailElems > 0){
        Shoutbox.updatesOff();
    }
  },
  
  
  
  /**
   * resets the shoutform to its original  state, clears all mediaType info and attached links, shows mediaTypeButtons
   * @param {Object} '#shoutMessage'
   */
  resetForm: function(){
    $('#sendForm').hide(); 
    $('#shoutMessage').val(Shoutbox.settings.labels.leave_shout);
    $('#inputShoutTitle, #inputThumbnailUrl, #inputExternalLink, #inputDescription, #inputMediaType, #inputServiceId, #inputImageUrl').val('');
    $('#sgMmMediaTypes').show();
  },
  
  /**
   * sets the form to the proper state, depending on what values are set in the hiiden fields
   */
  checkFormState: function(){
    if( $('#shoutMessage').val() === '' ){
      if( $('#inputExternalLink').val() === ''){
        $('#shoutMessage').val(Shoutbox.settings.labels.leave_shout);        
      }
      else{
        $('#shoutMessage').val(Shoutbox.settings.labels.leave_comment);
      }
    }
  }
};