#!/usr/bin/env python
#
# Copyright 2019 The Cobalt Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


"""A utility for generating a file list.

Each entry in the FileList contains the file path and a path relative to the
root directory that can be used for creating archives.

"""

import logging
import os

import _env  # pylint: disable=relative-import,unused-import

from starboard.build import port_symlink


class FileList(object):
  """Makes it easy to include files for things like archive operations."""

  def __init__(self):
    self.file_list = []  # List of 2-tuples: file_path, archive_path
    self.symlink_dir_list = []  # Same

  def AddAllFilesInPath(self, root_dir, sub_path):
    """Starting at the root path, the sub_paths are searched for files."""
    all_files = []
    all_symlinks = []
    if os.path.isfile(sub_path):
      self.AddFile(root_dir, sub_path)
    elif not os.path.isdir(sub_path):
      raise IOError('Expected root directory to exist: %s' % sub_path)
    for root, dirs, files in port_symlink.OsWalk(sub_path):
      for f in files:
        full_path = os.path.abspath(os.path.join(root, f))
        all_files.append(full_path)
      for dir_name in dirs:
        full_path = os.path.abspath(os.path.join(root, dir_name))
        if port_symlink.IsSymLink(full_path):
          all_symlinks.append(full_path)
    for f in all_files + all_symlinks:
      self.AddFile(root_dir, f)

  def AddAllFilesInPaths(self, root_dir, sub_paths):
    if not os.path.isdir(root_dir):
      raise IOError('Expected root directory to exist: ' + str(root_dir))
    for p in sub_paths:
      self.AddAllFilesInPath(root_dir=root_dir, sub_path=p)

  def AddFile(self, root_path, file_path):
    if port_symlink.IsSymLink(file_path):
      self.AddSymLink(root_path, file_path)
    else:
      archive_name = _OsGetRelpath(file_path, root_path)
      self.file_list.append([file_path, archive_name])

  def AddSymLink(self, relative_dir, link_file):
    rel_link_path = _OsGetRelpath(link_file, relative_dir)
    target_path = _ResolveSymLink(link_file)
    assert os.path.exists(target_path)
    rel_target_path = _OsGetRelpath(target_path, relative_dir)
    self.symlink_dir_list.append([relative_dir, rel_link_path, rel_target_path])

  def Print(self):
    for f in self.file_list:
      print 'File:    %s' % f
    for s in self.symlink_dir_list:
      print 'Symlink: %s' % s


def _ResolveSymLink(link_file):
  target_path = port_symlink.ReadSymLink(link_file)
  if os.path.exists(target_path):  # Absolute path
    return target_path
  else:
    return os.path.join(link_file, target_path)  # Relative path from link_file.


def _FallbackOsGetRelPath(path, start_dir):
  path = os.path.normpath(path)
  start_dir = os.path.normpath(start_dir)
  common_prefix = os.path.commonprefix([path, start_dir])
  split_list = common_prefix.split(os.sep)
  path_parts = path.split(os.sep)
  for _ in range(len(split_list)):
    path_parts = path_parts[1:]
  return os.path.normpath(os.path.join(*path_parts))


def _OsGetRelpath(path, start_dir):
  try:
    return os.path.relpath(path, start_dir)
  except ValueError:
    try:
      # Windows: nt paths checks the drive specifier, which is given by the
      # abspath operation.
      return os.path.relpath(os.path.abspath(path), os.path.abspath(start_dir))
    except ValueError:
      try:
        # Last resort: do a string comparison to get relative path.
        rel_path = _FallbackOsGetRelPath(path, start_dir)
        if not os.path.exists(os.path.join(start_dir, rel_path)):
          raise ValueError('% does not exist.' % os.path.abspath(rel_path))
        return rel_path
      except ValueError as err:
        logging.exception('Error %s while calling os.path.relpath(%s, %s)',
                          err, path, start_dir)


TYPE_NONE = 'NONE'
TYPE_SYMLINK_DIR = 'SYMLINK DIR'
TYPE_DIRECTORY = 'DIR'
TYPE_FILE = 'FILE'


def GetFileType(f):
  if not os.path.exists(f):
    return TYPE_NONE
  elif port_symlink.IsSymLink(f):
    return TYPE_SYMLINK_DIR
  elif os.path.isdir(f):
    return TYPE_DIRECTORY
  else:
    assert os.path.isfile(f)
    return TYPE_FILE
