# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/03_bytes.ipynb.

# %% auto 0
__all__ = ['Bytes']

# %% ../nbs/03_bytes.ipynb 4
import os, math
from dataclasses import KW_ONLY, dataclass, field
from typing import Union, List, Optional

# %% ../nbs/03_bytes.ipynb 6
from bytetype.units import (
    BYTE, KILOBYTE, MEGABYTE, GIGABYTE, TERABYTE,
    PETABYTE, EXABYTE, ZETTABYTE, YOTTABYTE
)

# %% ../nbs/03_bytes.ipynb 8
from bytetype.utils import (
    bytes_idx, bytes_to_size
)

# %% ../nbs/03_bytes.ipynb 10
from bytetype.enums import (
    ByteSize, BytesUnit
)

# %% ../nbs/03_bytes.ipynb 12
@dataclass
class Bytes:
    """A class for representing sizes in various byte units."""
    nbytes: int = field(default=0, repr=False,)
    round: Optional[int] = field(default=2, repr=False)
    
    unit: BytesUnit = field(default=BytesUnit.B, init=False)
    size: float = field(default=0.0, init=False)

    def __post_init__(self):
        self.unit = BytesUnit.from_bytes(self.nbytes)
        self.size = BytesUnit.calc_size(self.nbytes, self.round)

    def __repr__(self) -> str:
        return f'{self.size} {self.unit}'
    
    def __add__(self, other: Union['Bytes', int]):
        """Add two Bytes instances or a Bytes instance and a byte count.
        
        Parameters
        ----------
        other : Bytes or int
            The other Bytes instance or byte count.

        Returns
        -------
        Bytes
            The Bytes instance representing the total size.
        """
        if isinstance(other, Bytes):
            total_bytes = self.nbytes + other.nbytes
        else:
            total_bytes = self.nbytes + other
        return Bytes(total_bytes, round=self.round)

    def __sub__(self, other: Union['Bytes', int]):
        """Subtract a Bytes instance or a byte count from this Bytes instance.
        
        Parameters
        ----------
        other : Bytes or int
            The other Bytes instance or byte count.

        Returns
        -------
        Bytes
            The Bytes instance representing the remaining size.
        """
        if isinstance(other, Bytes):
            total_bytes = self.nbytes - other.nbytes
        else:
            total_bytes = self.nbytes - other
        if total_bytes < 0: total_bytes = 0
        return Bytes(total_bytes, round=self.round)
    
    def __mul__(self, other: Union['Bytes', int]):
        """Multiply this Bytes instance by a Bytes instance or a byte count.
        
        Parameters
        ----------
        other : Bytes or int
            The other Bytes instance or byte count.

        Returns
        -------
        Bytes
            The Bytes instance representing the total size.
        """
        if isinstance(other, Bytes):
            total_bytes = self.nbytes * other.nbytes
        else:
            total_bytes = self.nbytes * other
        return Bytes(total_bytes, round=self.round)

    def __truediv__(self, other: Union['Bytes', int]):
        """Divide this Bytes instance by a Bytes instance or a byte count.
        
        Parameters
        ----------
        other : Bytes or int
            The other Bytes instance or byte count.

        Returns
        -------
        Bytes
            The Bytes instance representing the total size.
        """
        if isinstance(other, Bytes):
            total_bytes = self.nbytes / other.nbytes
        else:
            total_bytes = self.nbytes / other
        return Bytes(total_bytes, round=self.decimals)

    @staticmethod
    def from_file(file_path: str, round: Optional[int] = 2) -> 'Bytes':
        """Create a Bytes instance representing the size of a file.
        
        Parameters
        ----------
        file_path : str
            The path to the file.
        decimals : int, optional
            The number of decimal places to round to (default is 2).

        Returns
        -------
        Bytes
            The Bytes instance representing the size of the file.
        """
        size = os.path.getsize(file_path)
        return Bytes(size, round=round)

    @staticmethod
    def from_dir(dir_path: str, round: Optional[int] = 2) -> 'Bytes':
        """Create a Bytes instance representing the total size of a directory.
        
        Parameters
        ----------
        dir_path : str
            The path to the directory.
        decimals : int, optional
            The number of decimal places to round to (default is 2).

        Returns
        -------
        Bytes
            The Bytes instance representing the total size of the directory.
        """
        total = 0
        for dirpath, dirnames, filenames in os.walk(dir_path):
            for f in filenames:
                fp = os.path.join(dirpath, f)
                if not os.path.islink(fp):
                    total += os.path.getsize(fp)
        return Bytes(total, round=round)
    
    def to_bytes(self) -> int:
        """Convert the Bytes instance to a byte count.

        Returns
        -------
        int
            The byte count.
        """
        return self.nbytes
    

    def __lt__(self, other: Union['Bytes', int]) -> bool:
        """Less than comparison between two Bytes instances or a Bytes instance and a byte count.

        Parameters
        ----------
        other : Bytes or int
            The other Bytes instance or byte count.

        Returns
        -------
        bool
            True if this Bytes instance is less than the other, False otherwise.
        """
        if isinstance(other, Bytes):
            return self.nbytes < other.nbytes
        else:
            return self.nbytes < other

    def __le__(self, other: Union['Bytes', int]) -> bool:
        """Less than or equal to comparison between two Bytes instances or a Bytes instance and a byte count.

        Parameters
        ----------
        other : Bytes or int
            The other Bytes instance or byte count.

        Returns
        -------
        bool
            True if this Bytes instance is less than or equal to the other, False otherwise.
        """
        if isinstance(other, Bytes):
            return self.nbytes <= other.nbytes
        else:
            return self.nbytes <= other

    def __gt__(self, other: Union['Bytes', int]) -> bool:
        """Greater than comparison between two Bytes instances or a Bytes instance and a byte count.

        Parameters
        ----------
        other : Bytes or int
            The other Bytes instance or byte count.

        Returns
        -------
        bool
            True if this Bytes instance is greater than the other, False otherwise.
        """
        if isinstance(other, Bytes):
            return self.nbytes > other.nbytes
        else:
            return self.nbytes > other

    def __ge__(self, other: Union['Bytes', int]) -> bool:
        """Greater than or equal to comparison between two Bytes instances or a Bytes instance and a byte count.

        Parameters
        ----------
        other : Bytes or int
            The other Bytes instance or byte count.

        Returns
        -------
        bool
            True if this Bytes instance is greater than or equal to the other, False otherwise.
        """
        if isinstance(other, Bytes):
            return self.nbytes >= other.nbytes
        else:
            return self.nbytes >= other

    def __eq__(self, other: Union['Bytes', int]) -> bool:
        """Equality comparison between two Bytes instances or a Bytes instance and a byte count.

        Parameters
        ----------
        other : Bytes or int
            The other Bytes instance or byte count.

        Returns
        -------
        bool
            True if this Bytes instance is equal to the other, False otherwise.
        """
        if isinstance(other, Bytes):
            return self.nbytes == other.nbytes
        else:
            return self.nbytes == other

    def __ne__(self, other: Union['Bytes', int]) -> bool:
        """Not equal to comparison between two Bytes instances or a Bytes instance and a byte count.

        Parameters
        ----------
        other : Bytes or int
            The other Bytes instance or byte count.

        Returns
        -------
        bool
            True if this Bytes instance is not equal to the other, False otherwise.
        """
        if isinstance(other, Bytes):
            return self.nbytes != other.nbytes
        else:
            return self.nbytes != other
