//
// Functions: Responds to updating $TDX properties.
//
(function(){
  let callbacks = [];
  
  window.TDGF_registerPropertyUpdateCallback = function(callback){
    callbacks.push(callback);
  };
  
  window.TDGF_onPropertiesUpdated = function(){
    callbacks.forEach(func => func($TDX));
  };
})();

//
// Function: Injects custom HTML into mustache templates.
//
window.TDGF_injectMustache = function(name, operation, search, custom){
  let replacement;
  
  switch(operation){
    case "replace": replacement = custom; break;
    case "append": replacement = search + custom; break;
    case "prepend": replacement = custom + search; break;
    default: throw "Invalid mustache injection operation. Only 'replace', 'append', 'prepend' are supported.";
  }
  
  const prev = TD.mustaches && TD.mustaches[name];
  
  if (!prev){
    crashDebug("Mustache injection is referencing an invalid mustache: " + name);
    return false;
  }
  
  TD.mustaches[name] = prev.replace(search, replacement);
  
  if (prev === TD.mustaches[name]){
    crashDebug("Mustache injection had no effect: " + name);
    return false;
  }
  
  return true;
};

//
// Function: Pushes the newest jQuery event to the beginning of the event handler list.
//
window.TDGF_prioritizeNewestEvent = function(element, event){
  const events = $._data(element, "events");
  
  const handlers = events[event];
  const newHandler = handlers[handlers.length - 1];
  
  for(let index = handlers.length - 1; index > 0; index--){
    handlers[index] = handlers[index - 1];
  }
  
  handlers[0] = newHandler;
};

//
// Function: Returns a display name for a column object.
//
window.TDGF_getColumnName = (function(){
  const titles = {
    "icon-home": "Home",
    "icon-mention": "Mentions",
    "icon-message": "Messages",
    "icon-notifications": "Notifications",
    "icon-follow": "Followers",
    "icon-activity": "Activity",
    "icon-favorite": "Likes",
    "icon-user": "User",
    "icon-search": "Search",
    "icon-list": "List",
    "icon-custom-timeline": "Timeline",
    "icon-dataminr": "Dataminr",
    "icon-play-video": "Live video",
    "icon-schedule": "Scheduled"
  };
  
  return function(column){
    return titles[column._tduck_icon] || "";
  };
})();

//
// Function: Adds a search column with the specified query.
//
onAppReady.push(() => execSafe(function setupSearchFunction(){
  const context = $._data(document, "events")["uiSearchInputSubmit"][0].handler.context;
  
  window.TDGF_performSearch = function(query){
    context.performSearch({ query, tduckResetInput: true });
  };
}, function(){
  window.TDGF_performSearch = function(){
    alert("error|This feature is not available due to an internal error.");
  };
}));

//
// Function: Plays sound notification.
//
window.TDGF_playSoundNotification = function(){
  document.getElementById("update-sound").play();
};

//
// Function: Plays video using the internal player.
//
window.TDGF_playVideo = function(videoUrl, tweetUrl, username){
  return if !videoUrl;
  
  $TD.playVideo(videoUrl, tweetUrl || videoUrl, username || null, function(){
    $('<div id="td-video-player-overlay" class="ovl" style="display:block"></div>').on("click contextmenu", function(){
      $TD.stopVideo();
    }).appendTo(app);
  });
};

//
// Function: Shows tweet detail, used in notification context menu.
//
execSafe(function setupShowTweetDetail(){
  ensurePropertyExists(TD, "ui", "updates", "showDetailView");
  ensurePropertyExists(TD, "controller", "columnManager", "showColumn");
  ensurePropertyExists(TD, "controller", "columnManager", "getByApiid");
  ensurePropertyExists(TD, "controller", "clients", "getPreferredClient");
  
  const showTweetDetailInternal = function(column, chirp){
    TD.ui.updates.showDetailView(column, chirp, column.findChirp(chirp) || chirp);
    TD.controller.columnManager.showColumn(column.model.privateState.key);
    
    $(document).trigger("uiGridClearSelection");
  };
  
  window.TDGF_showTweetDetail = function(columnId, chirpId, fallbackUrl){
    if (!TD.ready){
      onAppReady.push(function(){
        window.TDGF_showTweetDetail(columnId, chirpId, fallbackUrl);
      });
      
      return;
    }
    
    const column = TD.controller.columnManager.getByApiid(columnId);
    
    if (!column){
      if (confirm("error|The column which contained the tweet no longer exists. Would you like to open the tweet in your browser instead?")){
        $TD.openBrowser(fallbackUrl);
      }
      
      return;
    }
    
    const chirp = column.findMostInterestingChirp(chirpId);
    
    if (chirp){
      showTweetDetailInternal(column, chirp);
    }
    else{
      TD.controller.clients.getPreferredClient().show(chirpId, function(chirp){
        showTweetDetailInternal(column, chirp);
      }, function(){
        if (confirm("error|Could not retrieve the requested tweet. Would you like to open the tweet in your browser instead?")){
          $TD.openBrowser(fallbackUrl);
        }
      });
    }
  };
}, function(){
  window.TDGF_showTweetDetail = function(){
    alert("error|This feature is not available due to an internal error.");
  };
});

//
// Function: Screenshots tweet to clipboard.
//
execSafe(function setupTweetScreenshot(){
  window.TDGF_triggerScreenshot = function(){
    const hovered = getHoveredTweet();
    return if !hovered;
    
    const columnWidth = $(hovered.column.ele).width();
    const tweet = hovered.wrap || hovered.obj;
    
    const html = $(tweet.render({
      withFooter: false,
      withTweetActions: false,
      isInConvo: false,
      isFavorite: false,
      isRetweeted: false, // keeps retweet mark above tweet
      isPossiblySensitive: false,
      mediaPreviewSize: hovered.column.obj.getMediaPreviewSize()
    }));
    
    html.find("footer").last().remove(); // apparently withTweetActions breaks for certain tweets, nice
    html.find(".td-screenshot-remove").remove();
    
    html.find("p.link-complex-target,p.txt-mute").filter(function(){
      return $(this).text() === "Show this thread";
    }).remove();
    
    html.addClass($(document.documentElement).attr("class"));
    html.addClass($(document.body).attr("class"));
    
    html.css("background-color", getClassStyleProperty("stream-item", "background-color"));
    html.css("border", "none");
    
    for(let selector of [ ".js-quote-detail", ".js-media-preview-container", ".js-media" ]){
      const ele = html.find(selector);
      
      if (ele.length){
        ele[0].style.setProperty("margin-bottom", "2px", "important");
        break;
      }
    }
    
    const gif = html.find(".js-media-gif-container");
    
    if (gif.length){
      gif.css("background-image", 'url("'+tweet.getMedia()[0].small()+'")');
    }
    
    const type = tweet.getChirpType();
    
    if ((type.startsWith("favorite") || type.startsWith("retweet")) && tweet.isAboutYou()){
      html.addClass("td-notification-padded");
    }
    
    $TD.screenshotTweet(html[0].outerHTML, columnWidth);
  };
}, function(){
  window.TDGF_triggerScreenshot = function(){
    alert("error|This feature is not available due to an internal error.");
  };
});

//
// Function: Apply ROT13 to input selection.
//
window.TDGF_applyROT13 = function(){
  const ele = document.activeElement;
  return if !ele || !ele.value;
  
  const selection = ele.value.substring(ele.selectionStart, ele.selectionEnd);
  return if !selection;
  
  document.execCommand("insertText", false, selection.replace(/[a-zA-Z]/g, function(chr){
    const code = chr.charCodeAt(0);
    const start = code <= 90 ? 65 : 97;
    return String.fromCharCode(start + (code - start + 13) % 26);
  }));
};

//
// Function: Reloads all columns.
//
if (checkPropertyExists(TD, "controller", "columnManager", "getAll")){
  window.TDGF_reloadColumns = function(){
    Object.values(TD.controller.columnManager.getAll()).forEach(column => column.reloadTweets());
  };
}
else{
  window.TDGF_reloadColumns = function(){};
}

//
// Function: Reloads the website with memory cleanup.
//
window.TDGF_reload = function(){
  window.gc && window.gc();
  window.location.reload();
  
  window.TDGF_reload = function(){}; // redefine to prevent reloading multiple times
};