import json
from contextlib import contextmanager
import errno
import os

from plesk_mail_migrator.utils.exceptions import MailMigratorException


@contextmanager
def open_wrap_not_exists(filename, error_message):
    """Try to open file and if it does not exists - raise exception with specified error message.

    Returns the same data as built-in 'open' function.

    :type filename: str
    :type error_message: str
    """
    try:
        with open(filename) as fp:
            yield fp
    except IOError as e:
        if e.errno == errno.ENOENT:
            raise MailMigratorException(error_message)
        else:
            raise


def write_file_consistent(filename, contents):
    """Write contents to a file in a way so it either does not exists, or whole contents is inside of the file

    :type filename: str | unicode
    :type contents: str
    :rtype: None
    """
    # First, write data to a temporary file
    temp_filename = "%s.new" % filename
    with open(temp_filename, 'w') as fp:
        fp.write(contents)

    # Second, rename temporary file
    if os.path.exists(filename):
        # Remove the file if it exists - otherwise rename will fail on Windows
        os.unlink(filename)
    # Rename operation is atomic, so whole contents is inside of the destination file
    os.rename(temp_filename, filename)


def write_json_file_consistent(filename, data):
    """Write JSON contents to a file in a way so it either does not exists, or whole contents is inside of the file

    :type filename: str | unicode
    :type data: any
    :rtype: None
    """
    write_file_consistent(
        filename,
        contents=json.dumps(data, sort_keys=True, indent=4)
    )
