<?php


namespace CMSMSExt\FS;

use CMSMSExt\dbg\dbg;

/**
 * Class File
 *
 * @note: WIP
 * @package CMSMSExt\FS
 */
class File
{
  protected $_fn = '';
  protected $_lines = [];
  protected $_flags = \LOCK_EX;
  
  /**
   * Conform the path and filename
   * to unix style slashes
   *
   * @param string $fn
   *
   * @return string|string[]|null
   */
  protected function _conform_fn(string $fn = '')
  {
    if( empty($fn) ) { $fn = $this->_fn; }
    
    # either MS or other OS uses forward slashes for paths
    # so make sure there are no doubles or mixed slashes
    $fn = \str_replace("\\", '/', $fn );
    $fn = \preg_replace('/\/\/+/', '/', $fn );
  
    if( empty($fn) ) { $this->_fn = $fn; }
    
    return $fn;
  }
  
  /**
   * loads the file to the internal lines buffer array
   * if the loading fails it automatically resets the buffer
   * to prevent it being other than an array
   */
  protected function _load()
  {
    # this is deprecated in PHP 8.1, so we'll get rid of it soon
    if( \version_compare(\PHP_VERSION, '8.1.0') < 0 )
    {
      $old = \ini_get('auto_detect_line_endings');
      \ini_set('auto_detect_line_endings', TRUE);
      $this->_lines = \file($this->_fn, \FILE_IGNORE_NEW_LINES);
      \ini_set('auto_detect_line_endings', $old);
    }
    else
    {
      $this->_lines = \file($this->_fn, \FILE_IGNORE_NEW_LINES);
    }
    # -------------------------------------------------------------
    
    if(FALSE === $this->_lines) { $this->_reset(); }
  }
  
  /**
   * resets the internal lines buffer array
   */
  protected function _reset()
  {
    $this->_lines = [];
  }
  
  /**
   * public methods
   */
  
  /**
   * File constructor.
   * Given a valid filename
   * it loads a file as an array of lines
   * to the internal buffer
   *
   * @param string $file_name
   */
  public function __construct(string $file_name = '')
  {
    $this->setFileName($file_name);
    $this->_conform_fn();
    $this->_load();
  }
  
  public function append($data)
  {
    if( isset($data) )
    {
      if( \is_string($data) )
      {
        $t = \explode(PHP_EOL, $data);
        
        if( !empty($t) )
        {
          $this->_lines = [...$this->_lines, ...$t];
        }
      }
      elseif(\is_array($data) )
      {
        $this->_lines = [...$this->_lines, ...$data];
      }
      else
      {
        $this->_lines[] = [...$this->_lines, ...[(array)$data]];
      }
    }
    
    return $this;
  }
  
  /**
   * returns the buffer as a string
   * an attempt is made to get the EOLs right
   * @return string
   */
  public function __toString()
  {
    return $this->read();
  }
  
  public function setFileName(string $file_name = '')
  {
    $this->_fn = $file_name;
  }
  
  /**
   * returns the buffer as a string
   * an attempt is made to get the EOLs right
   * @return string
   */
  public function read() : string
  {
    return \implode(PHP_EOL, $this->_lines);
  }
  
  /**
   * resets and reloads the file
   * from the file name given
   * on the constructor
   *
   * @return $this
   */
  public function reload()
  {
    $this->_reset();
    $this->_load();
    
    return $this;
  }
  
  /**
   * given an array of lines
   * replaces the internal lines buffer array
   * with it
   *
   * @param array $lines
   *
   * @return $this
   */
  public function fromArray(array $lines = [])
  {
    $this->_lines = $lines;
    
    return $this;
  }
  
  /**
   * given a string of text
   * replaces the internal lines buffer array
   * with the array resulting of the attempt
   * to split the lines by a valid EOL character
   *
   * @param string $string
   * @param string $eol
   *
   * @return $this
   */
  public function fromString(string $string = '', string $eol = PHP_EOL)
  {
    $this->_lines = \explode($eol, $string);
    
    return $this;
  }
  
  /**
   * saves the internal lines buffer array
   * as a text file to the filename given on creation
   * or saves a copy to the given file name parameter if not empty
   *
   * @param string $file_name
   *
   * @return $this
   */
  public function save(string $file_name = '') : File
  {
    $fn = $this->_fn;
    
    if( !empty($file_name) )
    {
      $fn = $this->_conform_fn($fn);
    }
    
    if(
      !\is_dir(
                $dir = \implode( '/', \explode('/', $this->_fn, -1) )
              )
      && @!\mkdir($dir, 0777, TRUE) && !\is_dir($dir)
    )
    {
      throw new \RuntimeException(\sprintf('Directory "%s" was not created', $dir));
    }
    
    file_put_contents($fn, $this->read(), $this->_flags);
    
    return $this;
  }
  
  /**
   * Clears the state of the file and saves it.
   *
   * @return $this
   */
  function clear()
  {
    $this->_reset();
    $this->save();
    
    return $this;
  }
}

?>