<?php
/**
 * Tag Groups
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * @package    Tag Groups
 *
 * @author     Christoph Amthor
 * @copyright  2018 Christoph Amthor (@ Chatty Mango, chattymango.com)
 * @license    see official vendor website
 *
 * @since      1.24.0
 */

if ( ! class_exists( 'TagGroups_Transients' ) ) {

  /**
   * The main purpose of this class is to keep all cron-related information in one place.
   *
   */
  class TagGroups_Transients {

    /**
     * option name used to save array of used transient names
     */
    const TRANSIENT_NAMES = 'tag_group_used_transient_names';

    /**
     * Retrieves all transients created by Tag Groups Premium and deletes them
     *
     * @phpunit
     * @param  void
     * @return int
     */
    public static function purge_all_transients() {

      $count = 0;

      TagGroups_Error::verbose_log( '[Tag Groups Premium] Purging all transients.' );

      $count += TagGroups_Transients::delete_all_transients();

      TagGroups_Error::verbose_log( '[Tag Groups Premium] Purged %d transients.', $count );

      return $count;

    }

    /**
     * retrieve the array of all transient names that were used
     *
     * @return array
     */
    static function get_used_names() {

      if ( TagGroups_Transients::TRANSIENT_NAMES ) {

        return get_option( TagGroups_Transients::TRANSIENT_NAMES, array() );

      } else {

        TagGroups_Error::log( '[Tag Groups] Error retrieving array of transient names' );

        return array();

      }

    }

    /**
     * set the array of all transient names that were used
     *
     * @param  array  $used_transient_names
     * @return void
     */
    static function set_used_names( $used_transient_names ) {

      if ( TagGroups_Transients::TRANSIENT_NAMES ) {

        update_option( TagGroups_Transients::TRANSIENT_NAMES, $used_transient_names, true );

        // TagGroups_Error::verbose_log( '[Tag Groups] Saved array of %d transient name(s)', count( $used_transient_names ) );

      } else {

        TagGroups_Error::log( '[Tag Groups] Error saving array of transient names' );

      }

    }


    /**
     * Wrapper for delete_transient() that keeps track of the used transient names
     *
     * @param [type] $transient
     * @return void
     */
    static function delete_transient( $transient ) {

      if ( delete_transient( $transient ) ) {

        $used_transient_names = TagGroups_Transients::get_used_names();

        $key = array_search( $transient, $used_transient_names );

        unset( $used_transient_names[ $key ] );

        TagGroups_Transients::set_used_names( $used_transient_names );

      }

    }


    /**
     * Wrapper for set_transient() that keeps track of the used transient names
     *
     * @param  string  $transient
     * @param  mixed   $value
     * @param  integer $expiration
     * @return void
     */
    static function set_transient( $transient, $value, $expiration = null ) {

      if ( strlen( $transient ) > 172 ) {

        TagGroups_Error::log( '[Tag Groups] Transient name %s is too long!', $transient );

      }

      $used_transient_names = TagGroups_Transients::get_used_names();

      if ( ! in_array( $transient, $used_transient_names ) ) {

        $used_transient_names[] = $transient;

        TagGroups_Transients::set_used_names( $used_transient_names );

      }

      set_transient( $transient, $value, $expiration );

    }


    /**
     * Wrapper for get_transient() that keeps track of the used transients
     *
     * @param  string  $transient
     * @return mixed
     */
    static function get_transient( $transient ) {

        $value = get_transient( $transient );
  
        if ( false === $value ) {
  
          $used_transient_names = TagGroups_Transients::get_used_names();

          $key = array_search( $transient, $used_transient_names );
  
          if ( false !== $key ) {
          
            unset( $used_transient_names[ $key ] );
  
            TagGroups_Transients::set_used_names( $used_transient_names );
    
          }

        }
  
        return $value;
  
    }


    /**
     * Deletes all transients that we know about
     *
     * @param  string $substring Optional substring to match transient identifiers against
     * @return integer
     */
    static function delete_all_transients( $substring = '' ) {

      $count = 0;

      $used_transient_names = TagGroups_Transients::get_used_names();

      foreach ( $used_transient_names as $key => $transient ) {

        if ( ! empty( $substring ) && strpos( $transient, $substring ) === false ) {

          continue;

        }

        if ( delete_transient( $transient ) ) {

          $count++;

          unset( $used_transient_names[ $key ] );

        } else {

          /**
           * delete_transient may have returned false because that entry didn't exist
           */
          if ( false === get_transient( $key ) ) {

            $count++;

            unset( $used_transient_names[ $key ] );

          }
          
        }

      }

      if ( $count ) {

        TagGroups_Transients::set_used_names( $used_transient_names );

      }

      return $count;

    }


    /**
     * Deletes all expired transients that we know about
     *
     * @param string $substring
     * @return integer
     */
    static function delete_all_expired_transients( $substring = '' ) {

      $count = 0;

      $used_transient_names = TagGroups_Transients::get_used_names();

      foreach ( $used_transient_names as $key => $transient ) {

        if ( ! empty( $substring ) && strpos( $transient, $substring ) === false ) {

          continue;

        }

        if ( false === get_transient( $transient ) ) {
          // we never save the value false to transients, so here we know that it was expired or non-existent

          $count++;

          unset( $used_transient_names[ $key ] );

        }

      }

      if ( $count ) {

        TagGroups_Transients::set_used_names( $used_transient_names );

      }

      return $count;

    }


    /**
     * Since many front-end features depend on transients, we delete them here if needed
     *
     * @return void
     */
    public static function clear_transients_for_frontend_features() {

        self::delete_all_transients( 'tag_groups_group_terms' ); // including variants for languages (appended strings)

    }

  }

}
