// creational
package pattern

import (
	"fmt"
	"sync"
)

// 1. Singleton Pattern
type singleton struct {
	data string
}

var (
	instance *singleton
	once     sync.Once
)

func GetInstance() *singleton {
	once.Do(func() {
		instance = &singleton{data: "I am singleton"}
	})
	return instance
}

// 2. Factory Method Pattern
type Animal interface {
	Speak() string
}

type Dog struct{}
type Cat struct{}

func (d *Dog) Speak() string { return "Woof!" }
func (c *Cat) Speak() string { return "Meow!" }

func CreateAnimal(animalType string) Animal {
	switch animalType {
	case "dog":
		return &Dog{}
	case "cat":
		return &Cat{}
	default:
		return nil
	}
}

// 3. Abstract Factory Pattern
type Button interface {
	Paint()
}

type WinButton struct{}
type MacButton struct{}

func (w *WinButton) Paint() { fmt.Println("Windows button") }
func (m *MacButton) Paint() { fmt.Println("Mac button") }

type GUIFactory interface {
	CreateButton() Button
}

type WinFactory struct{}
type MacFactory struct{}

func (w *WinFactory) CreateButton() Button { return &WinButton{} }
func (m *MacFactory) CreateButton() Button { return &MacButton{} }

// 4. Builder Pattern
type House struct {
	windows int
	doors   int
	roof    string
}

type HouseBuilder struct {
	house *House
}

func NewHouseBuilder() *HouseBuilder {
	return &HouseBuilder{house: &House{}}
}

func (b *HouseBuilder) SetWindows(count int) *HouseBuilder {
	b.house.windows = count
	return b
}

func (b *HouseBuilder) SetDoors(count int) *HouseBuilder {
	b.house.doors = count
	return b
}

func (b *HouseBuilder) SetRoof(style string) *HouseBuilder {
	b.house.roof = style
	return b
}

func (b *HouseBuilder) Build() *House {
	return b.house
}

// 5. Prototype Pattern
type Prototype interface {
	Clone() Prototype
}

type ConcretePrototype struct {
	name string
}

func (p *ConcretePrototype) Clone() Prototype {
	return &ConcretePrototype{name: p.name}
}
