# pylint: disable=C0111,R0902,R0913
# Smartsheet Python SDK.
#
# Copyright 2016 Smartsheet.com, Inc.
#
# 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.

from __future__ import absolute_import

import logging
import os.path
from .models.folder import Folder
from . import fresh_operation


class Folders(object):

    """Class for handling Folders operations."""

    def __init__(self, smartsheet_obj):
        """Init Folders with base Smartsheet object."""
        self._base = smartsheet_obj
        self._log = logging.getLogger(__name__)

    def copy_folder(self, folder_id, container_destination_obj,
                    include=None, skip_remap=None):
        """Creates a copy of the specified Folder.

        Args:
            folder_id (int): Folder ID
            container_destination_obj
                (ContainerDestination): Container Destination object.
            include (list[str]): A comma separated list of
                elements to copy. Valid list values: attachments,
                attachments, cellLinks, data, discussions, filters, forms, ruleRecipients,
                rules, shares, all (deprecated).
            skip_remap (list[str]): A comma separated list
                of references to NOT re-map for the newly created resource.
                Valid list items: cellLinks, reports, sheetHyperlinks, sights

        Returns:
            Result
        """
        _op = fresh_operation('copy_folder')
        _op['method'] = 'POST'
        _op['path'] = '/folders/' + str(folder_id) + '/copy'
        _op['query_params']['include'] = include
        _op['query_params']['skipRemap'] = skip_remap
        _op['json'] = container_destination_obj

        expected = ['Result', 'Folder']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def create_folder_in_folder(self, folder_id, folder_obj):
        """Create a Folder in the specified Folder

        Args:
            folder_id (int): Folder ID
            folder_obj (Folder): Folder object.

        Returns:
            Result
        """
        if isinstance(folder_obj, str):
            folder_obj = Folder({
                'name': folder_obj
            })

        _op = fresh_operation('create_folder_in_folder')
        _op['method'] = 'POST'
        _op['path'] = '/folders/' + str(folder_id) + '/folders'
        _op['json'] = folder_obj

        expected = ['Result', 'Folder']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def create_sheet_in_folder(self, folder_id, sheet_obj):
        """Create a Sheet from scratch in the specified Folder.

        Args:
            folder_id (int): Folder ID
            sheet_obj (Sheet): Sheet object.

        Returns:
            Result
        """
        _op = fresh_operation('create_sheet_in_folder')
        _op['method'] = 'POST'
        _op['path'] = '/folders/' + str(folder_id) + '/sheets'
        _op['json'] = sheet_obj

        expected = ['Result', 'Sheet']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    # pylint: disable=invalid-name
    def create_sheet_in_folder_from_template(self, folder_id, sheet_obj,
                                             include=None):
        """Create a Sheet in the specified Folder from the specified Template.

        The Sheet object should be limited to the following
        attributes:

        name (required): need not be unique.
        fromId (required): the ID of the Template to use in creating the
        Sheet.

        The optional Include parameter is a list of elements to copy from
        the Template. It may include: data, attachments, discussions,
        cellLinks, forms

        Args:
            folder_id (int): Folder ID
            sheet_obj (Sheet): Sheet object.
            include (list[str]): A list of optional elements
                to include from the source Template. Valid list values:
                data, attachments, discussions, cellLinks, forms.

        Returns:
            Result
        """
        _op = fresh_operation('create_sheet_in_folder_from_template')
        _op['method'] = 'POST'
        _op['path'] = '/folders/' + str(folder_id) + '/sheets'
        _op['query_params']['include'] = include
        _op['json'] = sheet_obj

        expected = ['Result', 'Sheet']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    # pylint: enable=invalid-name

    def delete_folder(self, folder_id):
        """Delete the Folder (and its contents) specified in the request.

        Args:
            folder_id (int): Folder ID

        Returns:
            Result
        """
        _op = fresh_operation('delete_folder')
        _op['method'] = 'DELETE'
        _op['path'] = '/folders/' + str(folder_id)

        expected = ['Result', None]
        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def get_folder(self, folder_id, include=None):
        """Get the specified Folder (and list its contents).

        Args:
            folder_id (int): Folder ID
            include (list[str]): A comma-separated list of
                optional elements to include in the response. Valid list
                values: ownerInfo, sheetVersion, source.

        Returns:
            Folder
        """
        _op = fresh_operation('get_folder')
        _op['method'] = 'GET'
        _op['path'] = '/folders/' + str(folder_id)
        _op['query_params']['include'] = include

        expected = 'Folder'
        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def list_folders(self, folder_id, page_size=None, page=None,
                     include_all=None):
        """Get a list of top-level child Folders within the specified Folder.

        Args:
            folder_id (int): Folder ID
            page_size (int): The maximum number of items to
                return per page.
            page (int): Which page to return.
            include_all (bool): If true, include all results
                (i.e. do not paginate).

        Returns:
            IndexResult
        """
        _op = fresh_operation('list_folders')
        _op['method'] = 'GET'
        _op['path'] = '/folders/' + str(folder_id) + '/folders'
        _op['query_params']['pageSize'] = page_size
        _op['query_params']['page'] = page
        _op['query_params']['includeAll'] = include_all

        expected = ['IndexResult', 'Folder']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def move_folder(self, folder_id, container_destination_obj):
        """Moves the specified Folder to another location.

        Args:
            folder_id (int): Folder ID
            container_destination_obj
                (ContainerDestination): Container Destination object.

        Returns:
            Result
        """
        _op = fresh_operation('move_folder')
        _op['method'] = 'POST'
        _op['path'] = '/folders/' + str(folder_id) + '/move'
        _op['json'] = container_destination_obj

        expected = ['Result', 'Folder']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def update_folder(self, folder_id, folder_obj):
        """Update the specified Folder.

        Args:
            folder_id (int): Folder ID
            folder_obj (Folder): Folder object.

        Returns:
            Result
        """
        if isinstance(folder_obj, str):
            folder_obj = Folder({
                'name': folder_obj
            })

        _op = fresh_operation('update_folder')
        _op['method'] = 'PUT'
        _op['path'] = '/folders/' + str(folder_id)
        _op['json'] = folder_obj

        expected = ['Result', 'Folder']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def import_csv_sheet(self, folder_id, file, sheet_name=None, header_row_index=None, primary_column_index=None ):
        """Imports a sheet in the specified folder.

        Args:
            folder_id (int): folder ID
            file (string): path to CSV file.
            sheet_name (string): destination sheet name
            header_row_index (int): index (0 based) of row to be used for column names
            primary_column_index (int): index (0 based) of primary column

        Returns:
            Result
            """
        if not all(val is not None for val in ['folder_id', 'file']):
            raise ValueError(
                ('One or more required values '
                 'are missing from call to ' + __name__))

        return self._import_sheet(folder_id, file, "text/csv",
                                  sheet_name, header_row_index, primary_column_index)

    def import_xlsx_sheet(self, folder_id, file, sheet_name=None, header_row_index=None, primary_column_index=None ):
        """Imports a sheet in the specified folder.

        Args:
            folder_id (int): folder ID
            file (string): path to XLSX file.
            sheet_name (string): destination sheet name
            header_row_index (int): index (0 based) of row to be used for column names
            primary_column_index (int): index (0 based) of primary column

        Returns:
            Result
            """
        if not all(val is not None for val in ['folder_id', 'file']):
            raise ValueError(
                ('One or more required values '
                 'are missing from call to ' + __name__))

        return self._import_sheet(folder_id, file,
                                  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                                  sheet_name, header_row_index, primary_column_index)

    def _import_sheet(self, folder_id, file, file_type, sheet_name, header_row_index, primary_column_index):
        """Internal function used to import sheet"""

        if sheet_name is None:
            head, tail = os.path.split(file)
            sheet_name = tail or os.path.basename(head)

        _data = open(file, 'rb').read()

        _op = fresh_operation('import_sheet_into_folder')
        _op['method'] = 'POST'
        _op['path'] = '/folders/' + str(folder_id) + '/sheets/import'
        _op['headers'] = {'content-type': file_type,
                          'content-disposition': 'attachment'}
        _op['form_data'] = _data
        _op['query_params']['sheetName'] = sheet_name
        _op['query_params']['headerRowIndex'] = header_row_index
        _op['query_params']['primaryColumnIndex'] = primary_column_index

        expected = ['Result', 'Sheet']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response
