<?php

namespace monoformat {

include_once("monoformat_bithelpers.php");

trait FlagStruct {
    public static function fromJSON(array $json) {
        $myClass = static::class;
        $reflect = new \ReflectionClass($myClass);
        $properties = $reflect->getProperties(\ReflectionProperty::IS_PUBLIC);
        $result = new $myClass();
        foreach ($properties as $property) {
            $name = $property->getName();
            if (array_key_exists($name, $json)) {
                $result->$name = (bool) $json[$name];
            }
        }
        return $result;
    }

    public function toJSON(): array {
        $result = [];
        $myClass = static::class;
        $reflect = new \ReflectionClass($myClass);
        $properties = $reflect->getProperties(\ReflectionProperty::IS_PUBLIC);
        foreach ($properties as $property) {
            $name = $property->getName();
            $result[$name] = $this->$name;
        }
        return $result;
    }
}

enum SectionType : int {
    case AlwaysDrawn = 1;
    case TimeBasedDrawn = 2;
    case MultiTimeBasedDrawn = 3;
    case ExpiryDate = 31;
    case CustomFont = 32;

    public static function fromName(string $name): SectionType {
        foreach (self::cases() as $case) {
            if ($case->name === $name) {
                return $case;
            }
        }
        throw new \ValueError("$name is not a valid backing value for enum " . self::class);
    }
}

enum ElementType : int {
    case Image = 1;
    case Animation = 2;
    case HScrollImage = 3;
    case VScrollImage = 4;
    case Line = 5;
    case Box = 6;
    case ClippedText = 16;
    case HScrollText = 17;
    //case VScrollText = 18;
    case CurrentTime = 32;

    public static function fromName(string $name): SectionType {
        foreach (self::cases() as $case) {
            if ($case->name === $name) {
                return $case;
            }
        }
        throw new \ValueError("$name is not a valid backing value for enum " . self::class);
    }
}

class ScrollFlags {
    use FlagStruct;

    public bool $endless = false;
    public bool $invertDirection = false;
    public bool $padBefore = false;
    public bool $padAfter = false;

    public static function fromBitField(int $bitfield): ScrollFlags {
        $result = new ScrollFlags();
        $result->endless = isBitSet($bitfield, 0);
        $result->invertDirection = isBitSet($bitfield, 1);
        $result->padBefore = isBitSet($bitfield, 2);
        $result->padAfter = isBitSet($bitfield, 3);
        return $result;
    }

    public function toBitField(): int {
        $result = 0;
        maybeSetBit($result, 0, $this->endless);
        maybeSetBit($result, 1, $this->invertDirection);
        maybeSetBit($result, 2, $this->padBefore);
        maybeSetBit($result, 3, $this->padAfter);
        return $result;
    }
}

enum LineStyle : int {
    case Solid = 0;

    public static function fromName(string $name): SectionType {
        foreach (self::cases() as $case) {
            if ($case->name === $name) {
                return $case;
            }
        }
        throw new \ValueError("$name is not a valid backing value for enum " . self::class);
    }
}

class LineFlags {
    use FlagStruct;

    public bool $dark = false;

    public static function fromBitField(int $bitfield): LineFlags {
        $result = new LineFlags();
        $result->dark = isBitSet($bitfield, 0);
        return $result;
    }

    public function toBitField(): int {
        $result = 0;
        maybeSetBit($result, 0, $this->dark);
        return $result;
    }
}

enum FillPatternStyle : int {
    case Solid = 0;

    public static function fromName(string $name): SectionType {
        foreach (self::cases() as $case) {
            if ($case->name === $name) {
                return $case;
            }
        }
        throw new \ValueError("$name is not a valid backing value for enum " . self::class);
    }
}

class FillFlags {
    use FlagStruct;

    public bool $dark = false;

    public static function fromBitField(int $bitfield): FillFlags {
        $result = new FillFlags();
        $result->dark = isBitSet($bitfield, 0);
        return $result;
    }

    public function toBitField(): int {
        $result = 0;
        maybeSetBit($result, 0, $this->dark);
        return $result;
    }
}

class TextFlags {
    use FlagStruct;

    public bool $dark = false;
    public bool $autoWordWrap = false;

    public static function fromBitField(int $bitfield): TextFlags {
        $result = new TextFlags();
        $result->dark = isBitSet($bitfield, 0);
        $result->autoWordWrap = isBitSet($bitfield, 1);
        return $result;
    }

    public function toBitField(): int {
        $result = 0;
        maybeSetBit($result, 0, $this->dark);
        maybeSetBit($result, 1, $this->autoWordWrap);
        return $result;
    }
}

class TimeDisplayFlags {
    use FlagStruct;

    public bool $use12h = false;
    public bool $showHours = false;
    public bool $showMinutes = false;
    public bool $showSeconds = false;

    public static function fromBitField(int $bitfield): TimeDisplayFlags {
        $result = new TimeDisplayFlags();
        $result->use12h = isBitSet($bitfield, 0);
        $result->showHours = isBitSet($bitfield, 1);
        $result->showMinutes = isBitSet($bitfield, 2);
        $result->showSeconds = isBitSet($bitfield, 3);
        return $result;
    }

    public function toBitField(): int {
        $result = 0;
        maybeSetBit($result, 0, $this->use12h);
        maybeSetBit($result, 1, $this->showHours);
        maybeSetBit($result, 2, $this->showMinutes);
        maybeSetBit($result, 3, $this->showSeconds);
        return $result;
    }
}

} // namespace monoformat

?>
