class Origami::Graphics::State

def check_cmyk_color(color)

def check_cmyk_color(color)
    color.is_a?(::Array) and color.length == 4 and color.all? {|c| (0..1).include?(c) }
end

def check_color(space, color)

def check_color(space, color)
    valid_color =
        case space
        when Color::Space::DEVICE_GRAY
            check_gray_color(color)
        when Color::Space::DEVICE_RGB
            check_rgb_color(color)
        when Color::Space::DEVICE_CMYK
            check_cmyk_color(color)
        else
            raise InvalidColorError, "Unknown color space #{space}"
        end
    raise InvalidColorError, "Invalid color #{color.inspect} for #{space}" unless valid_color
end

def check_color_space(space)

def check_color_space(space)
    case space
    when Color::Space::DEVICE_GRAY, Color::Space::DEVICE_RGB, Color::Space::DEVICE_CMYK
    else
       raise InvalidColorError, "Unknown color space #{space}"
    end 
end

def check_gray_color(color)

def check_gray_color(color)
    color.is_a?(::Array) and color.length == 1 and (0..1).include?(color[0])
end

def check_rgb_color(color)

def check_rgb_color(color)
    color.is_a?(::Array) and color.length == 3 and color.all? {|c| (0..1).include?(c) }
end

def initialize

def initialize
    @stack = []
    @current_path = []
    @text_state = Text::State.new
    self.reset
end

def reset

def reset
    @ctm = Matrix.identity(3)
    @clipping_path = nil
    @stroking_colorspace = @nonstroking_colorspace = Color::Space::DEVICE_GRAY
    @stroking_color = @nonstroking_color = [ 0.0 ] #black
    @text_state.reset
    @line_width = 1.0
    @line_cap = LineCapStyle::BUTT_CAP
    @line_join = LineJoinStyle::MITER_JOIN
    @miter_limit = 10.0
    @dash_pattern = DashPattern.new([], 0)
    @rendering_intent = Color::Intent::RELATIVE
    @stroke_adjustment = false
    @blend_mode = Color::BlendMode::NORMAL
    @soft_mask = :None
    @alpha_constant = 1.0
    @alpha_source = false
end

def restore

def restore
    raise GraphicsStateError, "Cannot restore context : empty stack" if @stack.empty?
    @ctm, @clipping_path,
    @stroking_colorspace, @nonstroking_colorspace,
    @stroking_color, @nonstroking_color,
    @text_state, @line_width, @line_cap, @line_join,
    @miter_limit, @dash_pattern, @rendering_intent,
    @stroke_adjustment,
    @blend_mode, @soft_mask, @alpha_constant, @alpha_source = @stack.pop
end

def save

def save
    context =
    [
        @ctm, @clipping_path,
        @stroking_colorspace, @nonstroking_colorspace,
        @stroking_color, @nonstroking_color,
        @text_state, @line_width, @line_cap, @line_join,
        @miter_limit, @dash_pattern, @rendering_intent,
        @stroke_adjustment,
        @blend_mode, @soft_mask, @alpha_constant, @alpha_source
    ]
    @stack.push(context)
end

def set_nonstroking_color(color, space = @nonstroking_colorspace)

def set_nonstroking_color(color, space = @nonstroking_colorspace)
    check_color(space, color)
    @nonstroking_colorspace = space
    @nonstroking_color = color
end

def set_nonstroking_colorspace(space)

def set_nonstroking_colorspace(space)
    check_color_space(space, @nonstroking_color)
    @nonstroking_color_space = space
end

def set_stroking_color(color, space = @stroking_color_space)

def set_stroking_color(color, space = @stroking_color_space)
    check_color(space, color) 
    @stroking_colorspace = space
    @stroking_color = color
end

def set_stroking_colorspace(space)

def set_stroking_colorspace(space)
    check_color_space(space, @stroking_color)
    @stroking_color_space = space
end