// structural
package pattern

import (
	"fmt"
)

// 6. Adapter Pattern
type LegacyPrinter interface {
	Print(s string) string
}

type MyLegacyPrinter struct{}

func (p *MyLegacyPrinter) Print(s string) string {
	return fmt.Sprintf("Legacy: %s", s)
}

type ModernPrinter interface {
	PrintModern(s string) string
}

type PrinterAdapter struct {
	LegacyPrinter
}

func (p *PrinterAdapter) PrintModern(s string) string {
	return p.Print(s)
}

// 7. Bridge Pattern
type DrawAPI interface {
	DrawCircle(x, y, radius int)
}

type RedCircle struct{}
type GreenCircle struct{}

func (r *RedCircle) DrawCircle(x, y, radius int) {
	fmt.Printf("Drawing red circle at (%d,%d)\n", x, y)
}

func (g *GreenCircle) DrawCircle(x, y, radius int) {
	fmt.Printf("Drawing green circle at (%d,%d)\n", x, y)
}

type Shape struct {
	drawAPI DrawAPI
}

type Circle struct {
	Shape
	x, y, radius int
}

// 8. Composite Pattern
type Component interface {
	Operation() string
}

type Leaf struct {
	name string
}

type Composite struct {
	children []Component
}

func (l *Leaf) Operation() string {
	return l.name
}

func (c *Composite) Operation() string {
	result := "Branch("
	for _, child := range c.children {
		result += child.Operation() + " "
	}
	return result + ")"
}

// 9. Decorator Pattern
type Coffee interface {
	Cost() int
	Description() string
}

type SimpleCoffee struct{}

func (s *SimpleCoffee) Cost() int           { return 5 }
func (s *SimpleCoffee) Description() string { return "Simple coffee" }

type MilkDecorator struct {
	coffee Coffee
}

func (m *MilkDecorator) Cost() int {
	return m.coffee.Cost() + 2
}

func (m *MilkDecorator) Description() string {
	return m.coffee.Description() + ", milk"
}

// 10. Facade Pattern
type SubsystemA struct{}
type SubsystemB struct{}
type SubsystemC struct{}

func (s *SubsystemA) OperationA() string { return "Subsystem A" }
func (s *SubsystemB) OperationB() string { return "Subsystem B" }
func (s *SubsystemC) OperationC() string { return "Subsystem C" }

type Facade struct {
	sysA *SubsystemA
	sysB *SubsystemB
	sysC *SubsystemC
}

func (f *Facade) Operation() string {
	return f.sysA.OperationA() + " " + f.sysB.OperationB() + " " + f.sysC.OperationC()
}

// 11. Flyweight Pattern
type CharacterFlyweight struct {
	char rune
}

type CharacterFactory struct {
	chars map[rune]*CharacterFlyweight
}

func NewCharacterFactory() *CharacterFactory {
	return &CharacterFactory{chars: make(map[rune]*CharacterFlyweight)}
}

func (f *CharacterFactory) GetCharacter(c rune) *CharacterFlyweight {
	if f.chars[c] == nil {
		f.chars[c] = &CharacterFlyweight{char: c}
	}
	return f.chars[c]
}

// 12. Proxy Pattern
type Subject interface {
	Request() string
}

type RealSubject struct{}

func (s *RealSubject) Request() string {
	return "RealSubject: Handling request"
}

type Proxy struct {
	realSubject *RealSubject
}

func (p *Proxy) Request() string {
	if p.realSubject == nil {
		p.realSubject = &RealSubject{}
	}
	return "Proxy: " + p.realSubject.Request()
}
