@startuml
'https://plantuml.com/class-diagram
'TODO: abstract and static members should have {abstract} {static}
'TODO pricing and vat package
'TODO: only the methods that throw throws exception? Or du you have to add them all the way?
title CD
hide circle
skinparam linetype ortho
skinparam package {
    BackgroundColor LightYellow
}
'top to bottom direction
left to right direction
skinparam ClassAttributeIconSize 0
interface Comparable <<interface>> {
    + compareTo(Object o) : int
    }

together {
package startup {
    class Main{
        + <<static>> main(args : String[]) : void
    }
}
package view {
    class EndOfSaleView {
        # printCurrentState(sale : LimitedSaleView) : void
        # sortShoppingCart(listOfShoppingCartItems : List<ShoppingCartItem>) : void
        # shouldUpdate(isComplete : boolean) : boolean
        - createDiscountInfoString(discount : Amount, discountInfo : String) : void
    }
    class ErrorMessageHandler <<singleton>>{
        - createTime
    }
    class View {
        - contr: Controller
        + <<create>> View(contr : Controller) : View
    }
    abstract class TotalRevenue {
        # TotalRevenue
        # {abstract} doShowTotalRevenue(totalRevenue : Amount)
        # {abstract} handleErrors(e : Exception) : void
    }
    class TotalRevenueView {
        # doShowTotalRevenue(totalRevenue : Amount)
        # handleErrors(e : Exception) : void
    }
    abstract class SaleView {
        - listOfShoppingCartItems : List<ShoppingCartItem>
        - sale :LimitedSaleView
        # SaleView()
        # createSaleItemsInfoString() : String
        # addNewSaleInfoDetails(sale : LimitedSaleView) : void
        # {abstract} printCurrentState(sale : LimitedSaleView) : void
        # {abstract} sortShoppingCart(listOfShoppingCartItems : List<ShoppingCartItem>) : void
        # {abstract} shouldUpdate(isComplete : boolean) : boolean
    }
    class RunningSaleView {
        # printCurrentState(sale : LimitedSaleView) : void
        # sortShoppingCart(listOfShoppingCartItems : List<ShoppingCartItem>) : void
        # shouldUpdate(isComplete : boolean) : boolean
    }
}
package controller {
    class Controller{
        - saleObserver : List<SaleObserver>
        - printer : Printer
        - cashRegister : CashRegister
        - currentSale : Sale
        - logger : ErrorFileLogHandler
        + <<create>> Controller(printer : Printer) : Controller
        + addSaleObserver(observer : SaleObserver) : void
        + addCashRegisterObserver(observer : CashRegisterObserver) : void
        + startSale() : void {exception OperationFailedException}
        + registerItem(itemID : int) : void {exceptions=(ItemNotFoundInItemRegistryException, OperationFailedException, IllegalStateException)}
        + registerItem(itemID : int, quantity : int) : void {exceptions=(ItemNotFoundInItemRegistryException, OperationFailedException, IllegalStateException)}
        + endSale() : void {exception IllegalStateException}
        + registerCustomerToSale(customerID : int) void {exceptions=(IllegalStateException, CustomerNotFoundInCustomerRegistryException, OperationFailedException)}
        + pay(paidAmt : Amount) : void {exception IllegalStateException}
    }
}
package model {
    class Sale{
        - saleObserver : List<SaleObserver>
        - shoppingCart : HashMap<Integer, ShoppingCartItem>
'        - shoppingCart : Map<Integer, ShoppingCartItem>
        - payment : CashPayment
        - pricing : DiscountStrategy
        - customer : Customer
        - isComplete : boolean
        + <<create>> Sale() : Sale {exception PricingFailedException}
        + addItem(itemID : int, quantity : int) : void {exceptions=(ItemNotFoundInItemRegistryException, ItemRegistryException, PricingFailedException)}
        + addItem(itemInfo : ItemDTO, quantity : int) : void {exception PricingFailedException}
        + calculateTotalPrice() : Amount
        + calculateRunningTotal() : Amount
        + getTotalVATCosts() : Amount
        - calculateTotalVATAmount() : Amount
        + isComplete() : boolean
        ~ getPayment() : CashPayment
        + getTotalPricePaid() : Amount
        + getCollectionOfItems() : Collection<Item>
        + endSale() : void
        + addCustomerToSale(customerInfo : CustomerDTO) : void
        + getCustomer() : Customer
        + getDiscount() : Amount
        + createStringDiscountInfo() : String
        + pay(payment : CashPayment) : void
        + printReceipt(printer : Printer) : void
        + addSaleObservers(eventType : observers : Map<Event, List<SaleObserver>>) : void
        - notifyObservers(eventType : Event) : void
    }
    class ShoppingCartItem{
        - itemInfo : ItemDTO
        - timeOfUpdate : LocalDateTime
        - quantity : int
        - vatCalculation : VATStrategy
        + <<create>> ShoppingCartItem(itemInfo:ItemDTO) : ShoppingCartItem {exception PricingFailedException}
        + <<create>> ShoppingCartItem(itemInfo:ItemDTO, quantity : int): ShoppingCartItem {exception PricingFailedException}
        + addToQuantity(additionalQuantity : int) : void
        + getTotalSubPrice() : Amount
        + calculateTotalSubVATCosts() : Amount
        - calculateUnitVATCost() : Amount
        + getTimeOfUpdate() : LocalDateTime
        + getItemDTO() : ItemDTO
        + getItemID() : int
        + getQuantity() : int
        + getUnitPriceIncVAT() : Amount
        + getName() : String
        + equals(o Object) : boolean
        }
    class CashPayment{
        - paidAmt : Amount
        - totalCostPaid : Amount
        + <<create>> CashPayment(paidAmt:Amount): CashPayment
        ~ calculateTotalCost(paidSale:Sale) : void
         ~ calculateTotalCost(totalPrice : Amount, customer : Customer) : void
        ~ getPaidAmt() : Amount
        ~ getTotalCostPaid() : Amount
        ~ getChange() : Amount
        }
    class CashRegister{
        + <<static>> INITIAL_AMOUNT : double
        - cashRegisterObservers : List<CashRegisterObserver>
        - balance : Amount
        - revenue : Amount
        + <<create>> CashRegister(initialAmount : Amount) : CashRegister
        + <<create>> CashRegister(initialAmount : double) : CashRegister
        + <<create>> CashRegister() : CashRegister
        + addPayment(payment : CashPayment) : void
        + getBalance() : Amount
        + getRevenue() : Amount
        + addCashRegisterObserver(observer : CashRegisterObserver) : void
        + addCashRegisterObserver(observer : CashRegisterObserver) : void
        - notifyObservers() : void
    }
    class Receipt{
        - sale : Sale
        - timeOfSale : LocalDateTime
        - listOfShoppingCartItems : List<ShoppingCartItem>
        - locale : Locale
        - formatter : DateTimeFormatter
        - totalPricePreDiscount : Amount
        - totalPricePaid : Amount
        ~ <<create>> Receipt(sale: Sale) : Receipt
        - sortShoppingCart(listOfShoppingCartItems : List<ShoppingCartItem>) : void
        - createStringDiscountInfo() : String
        - createStringDiscountInfo() : String
        + toString() : String
    }
     class Amount{
        - currency : Currency
        - locale : Locale
        - amount : double
        + <<create>> Amount(amount : double, locale:Locale) : Amount
        + <<create>> Amount(amount : double) : Amount
        + <<create>> Amount(another : Amount) : Amount
        + <<create>> Amount() : Amount
        + minus(other : Amount) : Amount
        + plus(other : Amount) : Amount
        + plus(amounts : List<Amount>) : Amount
        + multiply(multiplier : double) : Amount
        + getAmount() : Double
        + toString() : String
        + equals(o : Object) : boolean
        + compareTo(o : Object) : int
    }
    class Customer {
        - customerID : int
        - customerType : CustomerType
        - bonusPoints : int
        + <<create>> Customer(customerID : int, customerType : CustomerType, bonusPoints : int) : Customer
        + <<create>> Customer(customerInfo : CustomerDTO)) : Customer
        + getBonusPoints() : int
        + addBonusPoints(paidAmount : Amount)
        + decreaseBonusPoints(usedBonusPoints : int) : void
        + equals(Object o)
    }
    interface SaleObserver <<interface>> {
        + updateSale(sale : LimitedSaleView)
    }
    interface CashRegisterObserver <<interface>> {
        + updateRevenue(totalRevenue : Amount) : void
    }
    interface LimitedSaleView <<interface>> {
        + isComplete() : boolean
        + getTotalPricePaid() : Amount
        + getTotalPrice() : Amount
        + calculateRunningTotal() : Amount
        + getTotalVATCosts() : Amount
        + getCollectionOfItems() : Collection<ShoppingCartItem>
        + getDiscount() : Amount
        + createStringDiscountInfo() : String
    }
    class LimitedSaleViewWrapper {
        - sale : Sale
        + <<create>> LimitedSaleViewWrapper(sale : Sale) : LimitedSaleViewWrapper
    }
}
package integration {
    package pricing {
        enum "//<<enumeration>>//\nCustomerType" as CustomerType {
        STUDENT,
        MEMBER
    }
        class DiscountFactory <<singleton>> {
            - {static} DISCOUNT_CLASS_NAME_KEY : String
            + getDiscountStrategy() : DiscountStrategy {exceptions = (ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException)}
            - createComposite(classNames : String[] {exceptions = (ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException)}
            - instantiateDiscountStrategy(className : String) : DiscountStrategy {exceptions = (ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException)}
        }
         interface DiscountStrategy <<interface>>{
            + getTotal(sale : Sale) : Amount
            + getDiscount() : Amount
        }
         class CompositeDiscountStrategy {
            - discountStrategies : List<DiscountStrategy>
            - usedDiscountStrategy : DiscountStrategy
            ~ <<create>> CompositeDiscountStrategy() : CompositeDiscountStrategy
            + addDiscountStrategy(discountStrategy : DiscountStrategy)
            + toString()
        }
         class MemberDiscount {
            - discountRate : double
            - discountAmount : Amount
            + toString() : String
        }
        class StudentDiscount {
            - discountRate : double
            - discountAmount : Amount
            + toString() : String
        }
        class Promotion {
            - threshold : Amount
            - bonusCheck : Amount
            - discountAmount : Amount
            - toString() : String
        }
        class VATFactory <<singleton>> {
            - {static} VAT_CLASS_NAME_KEY : String
            + getDefaultVATStrategy() : DiscountStrategy {exceptions = (ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException)}
            - instantiateVATStrategy(className : String) : DiscountStrategy {exceptions = (ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException)}
        }
        interface VATStrategy <<interface>> {
            + calculateVATForItem(item : ShoppingCartItem) : Amount
        }
        class SwedishVAT {
            - getVATRate(vatGroupCode : int): double
        }
    }
'     TODO: Go through all the dB singletons. Are they correct? Is the UML updated?
    interface IRegistryFactory <<interface>> {
       + getDefaultItemRegister() : ItemRegistry {exceptions=(ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException)}
       + getDefaultCustomerRegister() : CustomerRegistry {exceptions=(ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException)}
       + getDefaultAccountingSystem() : AccountingSystem {exceptions=(ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException)}
    }

    class FlatFileDatabaseFactory <<singleton>> {
        - ACCOUNTING_CLASS_NAME_KEY : String
        - CUSTOMER_CLASS_NAME_KEY : String
        - INVENTORY_CLASS_NAME_KEY : String
    }

    class RegistryHandler <<singleton>> {
        - accountingSystem : AccountingSystem
        - customerRegister : CustomerRegistry
        - itemRegistry : ItemRegistry
        - saleLog : SaleLog
        + updateRegistries(closedSale : Sale) : void
        + updateAccountingSystem(closedSale : Sale) : void
        + updateCustomerRegistry(closedSale : Sale) : void
        + updateItemRegistry(closedSale : Sale) : void
        + logSale(closedSale : Sale) : void
        + getCustomerInfo(customerID : int) : CustomerDTO {exception CustomerNotFoundInCustomerRegistryException}
        + getItemInfo(itemID : int) : ItemDTO {exception ItemNotFoundInItemRegistryException}
        + findSaleByCustomerID(customerID : int) : List<Sale>
    }

    interface AccountingSystem<T> <<interface>> {
        + updateRegistry(closedSale : Sale) : void {exception} {exception AccountingSystemException}
    }
    interface CustomerRegistry<T> <<interface>> {
        + getDataInfo(dataID T) : CustomerDTO {exceptions=(CustomerNotFoundInCustomerRegistryException, CustomerRegistryException)}
        + updateRegistry(closedSale : Sale) : void {exception CustomerRegistryException}
    }
    interface ItemRegistry<T> <<interface>> {
        + getDataInfo(dataID T) : ItemDTO {exceptions=(ItemNotFoundInItemRegistryException, ItemRegistryException)}
        + updateRegistry(closedSale : Sale) : void {exception ItemRegistryException}
    }

'     TODO Se över hela upplägget. Records och dylikt
    class AccountingSystemFlatFileDB <<singleton>>{
        - {static} CSV_DELIMITER : String
        - FILE_PATH_KEY : String
        - FLAT_FILE_DB_NAME _KEY: String
        - flatFileDb : File
        - recordHeader : string
        - records : Map<LocalDateTime, Record>
'        - records : HashMap<LocalDateTime, Record>
        - timeOfUpdate : LocalTime
        - totalRevenue : Amount
        - totalVatCosts : Amount
        - totalDiscounts : Amount
        - addRecordDataFromDb() : void {exception AccountingSystemException}
        - updateDatabase() : void {exception AccountingSystemException}
    }
'        note bottom : Record is a nested class
        class Record {
            - timeOfUpdate : LocalTime
            - totalAmount : Amount
            - totalVatAmount : Amount
            - discounts : Amount
            + <<create>>Record(timeOfUpdate : LocalTime, totalAmount : Amount, totalVatAmount : Amount, discounts : Amount)
            + toString() : String
        }

    class CustomerRegistryFlatFileDB <<singleton>> {
        - {static} CSV_DELIMITER : String
        - FILE_PATH_KEY : String
        - FLAT_FILE_DB_NAME _KEY: String
        - DATABASE_NOT_FOUND : int
        - flatFileDb : File
        - recordHeader : string
        - customerTable : Map<Integer, CustomerData>
'        - customerTable : HashMap<Integer, CustomerData>
        - addCustomerData() : void {exception CustomerRegistryException}
        - updateDatabase() :void {exception CustomerRegistryException}
    }
'        note bottom : CustomerData is a nested class
        class CustomerData {
            - customerID : int
            - customerType : CustomerType
            - bonusPoints : int
            + <<create>>CustomerData(customerID : int, customerType : CustomerType, bonusPoints : int)
            + toString() : String
        }

    class ItemRegistryFlatFileDB <<singleton>> {
        - {static} CSV_DELIMITER : String
        - FILE_PATH_KEY : String
        - FLAT_FILE_DB_NAME _KEY: String
        - DATABASE_NOT_FOUND : int
        - flatFileDb : File
        - recordHeader : string
        - inventoryTable : Map<Integer, ItemData>
'        - inventoryTable : HashMap<Integer, ItemData>
        - addItemData() : void {exception ItemRegistryException}
        - updateDatabase() : void {exception ItemRegistryException}
    }
'        note bottom : ItemData is a nested class
        class ItemData {
            - articleNo : int
            - name : String
            - description : String
            - price : Amount
            - vatGroupCode : int
            - inStore : int
            - sold : int
            + <<create>>ItemData(articleNo : int, name : String, \n description : String, price : Amount, vatGroupCode : int, \ninStore : int, sold : int)
            + toString() : String
        }

    class SaleLog{
        + sales : List<Sale>
        ~<<create>>SaleLog() : SaleLog
        ~ logSale(sale : Sale) : void
        ~ findSaleByCustomerID(customerID : int) : List<Sale>
    }
    class Printer{
        + <<create>>Printer() : Printer
        + printReceipt(receipt : Receipt) : void
         + printSaleLog(saleLog : SaleLog) : void
    }
    class TotalRevenueFileOutput {
        - FILE_SEPARATOR  : String
        - FILE_PATH : String
        - LOG_FILE_NAME : String
        - locale : Locale
        - formatter : DateTimeFormatter
        - revenueLogger : PrintWriter
        - logger : ErrorFileLogHandler
        + <<create>>TotalRevenueFileOutput() : TotalRevenueFileOutput {exception IOException}
        # doShowTotalRevenue(totalRevenue : Amount)
        # handleErrors(e : Exception) : void
        - createTime() : String
        }
}
package util{
    class ErrorFileLogHandler <<singleton>>{
        - FILE_SEPARATOR  : String
        - FILE_PATH : String
        - LOG_FILE_NAME : String
        - LINE_SEPARATOR  : String
        - logFile : PrintWriter
        - createTime() : String
    }
     interface Logger <T><<interface>> {
        + log(message : T) : void
    }
}

'interfaces
CashRegisterObserver <|-[dashed]- TotalRevenue
TotalRevenue <|- TotalRevenueView
TotalRevenue <|- TotalRevenueFileOutput

SaleObserver <|-[dashed]- SaleView
SaleView <|- EndOfSaleView
SaleView <|- RunningSaleView

DiscountStrategy <|-[dashed]- CompositeDiscountStrategy
DiscountStrategy <|-[dashed]- StudentDiscount
DiscountStrategy <|-[dashed]- Promotion
DiscountStrategy <|-[dashed]- MemberDiscount

Logger <|-[dashed]- ErrorFileLogHandler
Logger <|-[dashed]- ErrorMessageHandler

VATStrategy <|-[dashed]- CompositeVATStrategy
VATStrategy <|-[dashed]- SwedishVAT

IRegistryFactory <|-[dashed]- FlatFileDatabaseFactory

AccountingSystem <|-[dashed]- AccountingSystemFlatFileDB
CustomerRegistry <|-[dashed]- CustomerRegistryFlatFileDB
ItemRegistry <|-[dashed]- ItemRegistryFlatFileDB

LimitedSaleView <|-[dashed]- LimitedSaleViewWrapper

Comparable <|-[dashed]- Amount

'Nested classes
ItemData +-- ItemRegistryFlatFileDB
CustomerData +-- CustomerRegistryFlatFileDB
Record +-- AccountingSystemFlatFileDB

'Dependencies
Main --> View
Main -left-> Controller
Main ---> Printer
Main ---> RegistryHandler
Controller -up-> CashRegister
Controller --> SaleLog
Controller --> CustomerRegistryFlatFileDB
Controller --> AccountingSystemFlatFileDB
Controller --> ItemRegistryFlatFileDB
Controller --> RegistryHandler
RegistryHandler --> CustomerRegistryFlatFileDB
RegistryHandler --> AccountingSystemFlatFileDB
RegistryHandler --> ItemRegistryFlatFileDB
RegistryHandler --> SaleLog
View -right-> Controller
Controller --> Sale
Controller --> CashPayment
Sale --> CashPayment
Receipt <-- Sale
Sale --> Printer
Sale --> ShoppingCartItem
Sale --> Amount
@enduml

@startuml
'title DTO
' //TODO Ska vi ha en customerDTO och customerDb?
' //TODO Ska DTO:erna flyttas till CD?
hide circle
skinparam ClassAttributeIconSize 0
skinparam linetype ortho
skinparam package {
    BackgroundColor LightYellow
}
    package dto {
        class ItemDTO{
            - itemId : int
            - name : String
            - description : String
            - price : Amount
            - vat : VAT
            +<<create>> ItemDTO() : ItemDTO
            + equals(o : Object)
        }
        class CustomerDTO{
'            // TODO ska discount finnas med i SaleDTO?
            - customerID : int
            - customerType : CustomerType
            - bonusPoints : int
            +<<create>>DiscountDTO(customerID : int, customerType : CustomerType, bonusPoints : int) : DiscountDTO
            + equals(o : Object) : boolean
'        note bottom : Attributes TBD based on Discount Rules.
        }
    }
note top: getters, toString and equals are included as methods for all DTO attributes
@enduml

@startuml
skinparam style strictuml
participant ":Main" as Main
participant "printer:Printer" as printer
participant "registerCreator:RegisterCreator" as registerCreator
participant "saleLog:SaleLog" as saleLog
participant ":AccountingSystem" as AccountingSystemFlatFileDB

participant ":ItemRegistry" as ItemRegistryFlatFileDB
participant "contr:Controller" as contr
participant "cashRegister : CashRegister" as cashRegister
participant "view : View" as view
' user -> Main: main()
activate Main
create printer
autonumber 1
Main -[dashed]->> printer : <<create>>\n printer = Printer() : Printer

create registerCreator
autonumber 2
Main -[dashed]->> registerCreator : <<create>>\n registerCreator = RegistryHandler() : RegistryHandler
activate registerCreator

autonumber 2.1
create saleLog
registerCreator -[dashed]->> saleLog : <<create>>\n saleLog = SaleLog() : SaleLog

create AccountingSystemFlatFileDB
autonumber 2.2
registerCreator -> AccountingSystemFlatFileDB : <<static>>\ngetInstance() : AccountingSystemFlatFileDB

create CustomerRegistry
autonumber 2.3
registerCreator -> CustomerRegistry : <<static>>\ngetInstance() : CustomerRegistry
'activate CustomerRegistryFlatFileDB
'deactivate CustomerRegistryFlatFileDB

create ItemRegistryFlatFileDB
autonumber 2.4
registerCreator -> ItemRegistryFlatFileDB: <<static>>\ngetInstance() : ItemRegistryFlatFileDB
'activate ItemRegistry
'deactivate ItemRegistry
deactivate registerCreator

autonumber 3
create contr
Main -[dashed]->> contr : <<create>>\n contr = Controller(printer : Printer, registerCreator : RegistryHandler) : Controller
activate contr

autonumber 3.1
contr -> registerCreator : saleLog = getSaleLog() : SaleLog
activate registerCreator
deactivate registerCreator

autonumber 3.2
contr -> registerCreator : accountingSystem = getAccountingSystem() : AccountingSystemFlatFileDB
activate registerCreator
deactivate registerCreator

autonumber 3.3
contr -> registerCreator : customerRegistry = getCustomerRegistry() : CustomerRegistry
activate registerCreator
deactivate registerCreator

autonumber 3.4
contr -> registerCreator : itemRegistry = getItemRegistry() : ItemRegistryFlatFileDB
activate registerCreator
deactivate registerCreator

create cashRegister
autonumber 3.5
contr -[dashed]->> cashRegister : <<create>>\n cashRegister = CashRegister(initialAmount: int) : CashRegister
'activate cashRegister
'deactivate cashRegister
'TODO ska jag lägga till att contr skapar en Lista för SaleObservers?
deactivate contr

create view
autonumber 4
Main -[dashed]->> view : <<create>>\n View(contr: Controller):View
activate view

autonumber 5
view -> contr : addSaleObserver(new SaleObserver() : SaleObserver) : void
activate contr
deactivate contr
deactivate view
deactivate Main
'TODO ska jag lägga till att view skapar observers?
'TODO ska jag lägga till att view anropar contr för alla RegisterObservers?
'TODO ska jag lägga till att view anropar contr för alla SaleObservers?

@enduml

@startuml
skinparam style strictuml

'autoactivate on 'TODO activationbars!!!!!!!
' actor user
hide unlinked
'title "startSale"
participant ":View" as View
participant "contr : Controller" as contr
participant "currentSale : Sale" as currentSale
participant ": DiscountFactory" as DiscountFactory
participant "saleObservers : List<SaleObserver>" as saleObservers

autonumber 1
View -> contr : startSale(): void
activate contr

autonumber 1.1
create currentSale
contr -[dashed]->> currentSale :  <<create>>\n currentSale = Sale() : Sale
activate currentSale
autonumber 1.1.1
create saleObservers
currentSale -[dashed]->> saleObservers : <<create>>\n observers = ArrayList<SaleObserver>() : ArrayList
autonumber 1.1.2
currentSale -> DiscountFactory : <<static>>\n discountFactory = getInstance() : DiscountFactory
activate DiscountFactory
deactivate DiscountFactory
currentSale -> DiscountFactory : pricing = getDiscountStrategy() : DiscountStrategy

'Hur lägga till brytningen som Leif har i sitt exempel?
autonumber 1.1.3
activate DiscountFactory
autonumber stop
currentSale <<- DiscountFactory : <<exception>>\nClassNotFoundException
currentSale <<- DiscountFactory : <<exception>>\nInvocationTargetException
currentSale <<- DiscountFactory : <<exception>>\nNoSuchMethodException
currentSale <<- DiscountFactory : <<exception>>\nInstantiationException
currentSale <<- DiscountFactory : <<exception>>\nIllegalAccessException
deactivate DiscountFactory
contr <<- currentSale : <<exception>>\nOperationFailedException
deactivate currentSale
View <<- contr : <<exception>>\nOperationFailedException
autonumber 1.2
contr -> currentSale : addAllSaleObservers(saleObservers : List<SaleObserver>) : void
activate currentSale
autonumber 1.2.1
currentSale -> saleObservers : addAll(observers : List<SaleObserver>) : void
activate saleObservers
deactivate saleObservers
deactivate currentSale

deactivate contr

autonumber stop
@enduml

@startuml
skinparam style strictuml

'title registerItem
'REGISTERITEM
hide unlinked
participant ": View" as View
participant "contr\n: Controller" as contr
participant "currentSale\n: Sale" as currentSale
participant "shoppingCart\n: Map<Integer, ShoppingCartItem>" as shoppingCart
participant ": RegistryHandler" as RegistryHandler
'interface ": ItemRegistry" as ItemRegistry
participant "<<interface>>\n: ItemRegistry" as ItemRegistry
participant "existingShoppingCartItem \n: ShoppingCartItem" as oldItem
participant "newShoppingCartItem\n: ShoppingCartItem" as newItem

loop moreItems
'[validIdentifier]
    alt singleItem
        autonumber 1
        View -> contr : registerItem(itemID:int) : void
        activate View
        activate contr
        autonumber 1.1
        contr -> contr : registerItem(itemID:int, 1 : int) : void
        activate contr
        deactivate contr
        deactivate contr

   else else
        autonumber 1
        View -> contr : registerItem(itemID:int, quantity:int) : void
        activate contr
   end
        autonumber 1.2
        contr -> currentSale : addItem(itemID : int, quantity:int) : void
        activate currentSale
            autonumber 1.2.1
            currentSale -> shoppingCart : existingShoppingCartItem = \nget.(itemID : int) : ShoppingCartItem
                activate shoppingCart
                deactivate shoppingCart
            alt existingShoppingCartItem != null
                autonumber 1.2.2
                currentSale -> oldItem : addToQuantity(quantity : int) : void
            ref over shoppingCart : Notify Sale Observers
                activate oldItem
                deactivate oldItem
            else
                autonumber 1.2.1
                currentSale -> RegistryHandler : itemInfo = RegistryHandler\n\t\t.getInstance()\n\t\t.getItemInfo(itemID : int) : ItemDTO
                ref over RegistryHandler, ItemRegistry
                    Database call
                end ref
                activate RegistryHandler
                autonumber stop
                currentSale <<- RegistryHandler : <<exception>>\nItemNotFoundInItemRegistryException
                currentSale <<- RegistryHandler : <<exception>>\nItemRegistryException
                deactivate RegistryHandler

                autonumber 1.2.2
                currentSale -> currentSale : addItem(itemInfo : ItemDTO, quantity : int) : void
                activate currentSale
                autonumber 1.2.2.1
                create newItem
                currentSale -[dashed]->> newItem : <<create>> \n newShoppingCartItem = \n ShoppingCartItem(itemInfo : ItemDTO, quantity : int) : ShoppingCartItem
                activate newItem
                ref over newItem : VAT Strategy
                autonumber stop
                 currentSale <<- newItem : <<exception>>\nPricingFailedException
                deactivate newItem
                currentSale -> shoppingCart : put(\n\titem.itemID():int, \n\tnewShoppingCartItem : ShoppingCartItem\n) : ShoppingCartItem
                activate shoppingCart
                deactivate shoppingCart
            ref over shoppingCart : Notify Sale Observers
            end
                deactivate currentSale

'        activate currentSale
                autonumber stop
                    contr <<- currentSale : <<exception>>\nItemNotFoundInItemRegistryException
                    contr <<- currentSale : <<exception>>\nItemRegistryException
                    ref over contr : notify developer, log error

'            autonumber 1.2.3
'            currentSale -> currentSale
'            activate currentSale
'            deactivate currentSale
            deactivate currentSale
                autonumber stop
                    View <<- contr : <<exception>>\nItemNotFoundInInRegistryException
                    ref over View : notify user, error message
                    View <<- contr : <<exception>>\nOperationFailedException
                    ref over View : notify user, error message
        autonumber stop

        deactivate contr
        deactivate View
end

autonumber stop
@enduml
@startuml

skinparam style strictuml
mainframe **sd** Notify Sale Observers
participant ": Sale" as Sale
participant "<<interface>>\n: LimitedSaleView" as LimitedSaleView
participant "saleObservers : List<SaleObserver>" as saleObservers

-> Sale : [some sale update]
activate Sale
Sale -> Sale : notifyObservers() : void
activate Sale
create LimitedSaleView
Sale -[dashed]->> LimitedSaleView : <<create>>\n limitedSaleView = LimitedSaleViewWrapper(sale : Sale) : LimitedSaleViewWrapper
loop for each SaleObserver in saleObservers
    Sale -> saleObservers : updateSale(limitedSaleView : LimitedSaleView) : void
    activate saleObservers
    deactivate saleObservers
end loop

@enduml
@startuml

skinparam style strictuml
mainframe **sd** Notify Cash Register Observers
participant ": CashRegister" as CashRegister
participant "cashRegisterObservers\n: List<CashRegisterObserver>" as cashRegisterObservers

-> CashRegister : addPayment()
activate CashRegister
CashRegister -> CashRegister : notifyObservers() : void
activate CashRegister
loop for each CashRegisterObserver in cashRegisterObservers
    CashRegister -> cashRegisterObservers : updateRevenue(revenue : Amount) : void
    activate cashRegisterObservers
    deactivate cashRegisterObservers
end loop

@enduml
@startuml
skinparam style strictuml
'title EndSale

participant ":View" as View
participant "contr:Controller" as contr
participant "currentSale:Sale" as currentSale

autonumber 1
View -> contr : endSale() : void
activate View
activate contr
autonumber 1.1
contr -> currentSale : endSale (): void
activate currentSale
            ref over currentSale
                Notify Sale Observers
            end ref
deactivate currentSale
deactivate contr
deactivate View

autonumber stop
@enduml

@startuml
skinparam style strictuml
'title registerCustomerToSale

participant ": View" as View
participant "contr : Controller" as contr
participant ": CustomerRegistry" as CustomerRegistry
participant "currentSale : Sale" as currentSale
participant ": Customer" as customer

autonumber 1
View -> contr : registerCustomerToSale(customerID:int): void
activate View
activate contr
autonumber 1.1
'create CustomerRegistry
contr -> CustomerRegistry : customerInfo = \ngetCustomerInfo(customerID:int) : CustomerDTO
activate CustomerRegistry
autonumber stop
contr <<- CustomerRegistry : <<exception>>\nCustomerNotFoundInCustomerRegistryException
contr <<- CustomerRegistry : <<exception>>\nCustomerRegistryException
deactivate CustomerRegistry
View <<- contr : <<exception>>\nCustomerNotFoundInCustomerRegistryException
View <<- contr : <<exception>>\nOperationFailedException
autonumber 1.2
contr -> currentSale : addCustomerToSale(customerInfo:CustomerDTO): void
activate currentSale
create customer
autonumber 1.2.1
currentSale -[dashed]-> customer : <<create>>\nCustomer(customerInfo : CustomerDTO) \n: Customer
activate customer
deactivate customer
deactivate customer

deactivate contr
deactivate View

autonumber stop
@enduml

@startuml
skinparam style strictuml
'title addPayment

'TODO: HÄR ÄR DU.
participant ": View" as View
participant "contr : Controller" as contr
participant "payment : CashPayment" as payment
participant "currentSale : Sale" as currentSale
participant "cashRegister : CashRegister" as cashRegister
participant "currentReceipt : Receipt" as currentReceipt
participant "printer : Printer" as printer

activate View
autonumber 1
View -> contr : pay(paidAmt : Amount) : void
activate contr
create payment
autonumber 1.1
contr -[dashed]->> payment : <<create>> \npayment = \nCashPayment(paidAmt:Amount) : CashPayment
autonumber 1.2
contr -> currentSale : pay(payment:CashPayment) : void
activate currentSale
ref over currentSale, payment
Pricing; discount and customer bonus points strategy
'TODO ref:
end
deactivate currentSale

deactivate currentSale
deactivate payment
deactivate currentSale
autonumber 1.3
contr -> cashRegister : addPayment (payment:CashPayment) : void
activate cashRegister
autonumber 1.3.1
cashRegister -> payment : getPaidAmt() : Amount
activate payment
deactivate payment
cashRegister -> payment : getChange() : Amount
activate payment
deactivate payment
cashRegister -> payment : getTotalCostPaid() : Amount
activate payment
deactivate payment
ref over cashRegister
Notify Cash Register Observers
end ref
deactivate cashRegister

ref over contr, currentSale
Log sale and update external systems
'TODO ref:
'participant "contr : Controller" as contr
'participant "currentSale : Sale" as currentSale
'participant "saleLog:SaleLog" as saleLog
'participant ": AccountingSystemFlatFileDB" as AccountingSystemFlatFileDB
'participant "customerRegistry : CustomerRegistry" as customerRegistry
'participant "itemRegistry : ItemRegistry" as itemRegistry
'autonumber 1.4
'contr -> saleLog:logSale(currentSale : Sale):void
'activate saleLog
'deactivate saleLog
'
'autonumber 1.5
'contr -> AccountingSystemFlatFileDB : updateToAccounting(currentSale : Sale): void
'activate AccountingSystemFlatFileDB
'autonumber 1.5.1
'AccountingSystemFlatFileDB -> AccountingSystemFlatFileDB : updateDatabase() :void
'activate AccountingSystemFlatFileDB
'deactivate AccountingSystemFlatFileDB
'deactivate AccountingSystemFlatFileDB
'
'autonumber 1.6
'contr -> customerRegistry : updateToAccounting(currentSale : Sale): void
'activate customerRegistry
'autonumber 1.6.1
'customerRegistry -> customerRegistry : updateDatabase() :void
'activate customerRegistry
'deactivate customerRegistry
'deactivate customerRegistry
'
'autonumber 1.7
'contr -> itemRegistry : updateRegistry(currentSale : Sale)
'activate itemRegistry
'autonumber 1.7.1
'itemRegistry -> itemRegistry : updateDatabase() :void
'activate itemRegistry
'deactivate itemRegistry
'deactivate itemRegistry
'deactivate currentSale
end ref
autonumber 1.4
contr -> currentSale : printReceipt(printer:Printer) : void
activate currentSale
create currentReceipt
autonumber 1.4.1
currentSale -[dashed]->> currentReceipt : <<create>>\n receipt = \n Receipt(sale:Sale) : Receipt
'activate currentReceipt
'deactivate currentReceipt
autonumber 1.4.2
currentSale -> printer :printReceipt(receipt:Receipt):void
activate printer
deactivate printer
deactivate currentSale
deactivate contr
deactivate View
autonumber stop

@enduml
@startuml
mainframe **sd** Pricing; discount and customer bonus points strategy
participant "currentSale : Sale" as currentSale
participant "payment : CashPayment" as payment
participant "pricing : CompositeDiscountStrategy" as pricing
participant "discountStrategies :\n List<DiscountStrategy>" as discountStrategies
participant "strategy : DiscountStrategy" as strategy
participant "customer : Customer" as customer

skinparam style strictuml

-> currentSale : pay(payment : CashPayment) : void
activate currentSale
currentSale -> payment : calculateTotalCost(currentSale : Sale) : void
activate payment
payment -> currentSale : totalCostPaid =\n getTotalPrice() : Amount
activate currentSale
currentSale -> pricing : getTotal(currentSale : Sale) : Amount
activate pricing
pricing -> currentSale : lowestTotalPrice =\n calculateRunningTotal() : Amount
activate currentSale
deactivate currentSale
loop i.hasNext
    pricing -> discountStrategies : strategy = i.next() : DiscountStrategy
    activate discountStrategies
    deactivate discountStrategies
    pricing -> strategy : total =\ngetTotal(currentSale)
    activate strategy
    deactivate strategy
    opt lowestTotalPrice > total
        pricing -> pricing : lowestTotalPrice = total
        pricing -> pricing : usedDiscountStrategy = strategy
    end opt
    deactivate pricing
end loop

payment -> currentSale : customer =\n getCustomer() : Customer
opt customer != null
payment ->  customer : addBonusPoints(totalCostPaid : Amount)
end opt
deactivate currentSale
@enduml
