Андон обнови решението на 06.12.2015 17:58 (преди над 2 години)
+package main
+
+import (
+        "encoding/json"
+        "encoding/xml"
+        "fmt"
+        "sync"
+)
+
+type Library interface {
+        AddBookJSON(data []byte) (int, error)
+
+        AddBookXML(data []byte) (int, error)
+
+        Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
+}
+
+type LibraryRequest interface {
+        GetType() int
+
+        GetISBN() string
+}
+
+type LibraryResponse interface {
+        GetBook() (fmt.Stringer, error)
+
+        GetAvailability() (int,int)
+}
+
+type Author struct {
+        FirstName string
+        LastName  string
+}
+
+type Book struct {
+        isbn    string
+        title   string
+        author  Author
+        genre   string
+        pages   int
+        ratings []float64
+}
+
+func (a *Author) UnmarshalJSON(data []byte) error {
+        var jsonData struct{ first_name, last_name string }
+
+        if err := json.Unmarshal(data, jsonData); err != nil {
+                return err
+        }
+
+        a.FirstName = jsonData.first_name
+        a.LastName = jsonData.last_name
+
+        return nil
+}
+
+func (b *Book) UnmarshalJSON(rawData []byte) error {
+        var jsonData struct {
+                isbn, title, author, genre string
+                pages                      int
+                ratings                    []float64
+        }
+
+        if err := json.Unmarshal(rawData, jsonData); err != nil {
+                return err
+        }
+
+        if err := json.Unmarshal([]byte(jsonData.author), b.author); err != nil {
+                return err
+        }
+
+        b.isbn = jsonData.isbn
+        b.title = jsonData.title
+        b.genre = jsonData.genre
+        b.pages = jsonData.pages
+        b.ratings = jsonData.ratings
+        return nil
+}
+
+func (a *Author) UnmarshalXML(data []byte) error {
+        var xmlData struct{ first_name, last_name string }
+
+        if err := xml.Unmarshal(data, xmlData); err != nil {
+                return err
+        }
+
+        a.FirstName = xmlData.first_name
+        a.LastName = xmlData.last_name
+
+        return nil
+}
+
+func (b *Book) UnmarshalXML(rawData []byte) error {
+        var xmlData struct {
+                isbn, title, author, genre string
+                pages                      int
+                ratings                    []float64
+        }
+
+        if err := xml.Unmarshal(rawData, xmlData); err != nil {
+                return err
+        }
+
+        if err := xml.Unmarshal([]byte(xmlData.author), b.author); err != nil {
+                return err
+        }
+
+        b.isbn = xmlData.isbn
+        b.title = xmlData.title
+        b.genre = xmlData.genre
+        b.pages = xmlData.pages
+        b.ratings = xmlData.ratings
+        return nil
+}
+
+func (b *Book) String() string {
+        return fmt.Sprintf("[%s] %s от %s", b.isbn, b.title, b.author)
+}
+
+type LibError struct {
+        errorMessage string
+}
+
+func (e LibError) Error() string {
+        return e.errorMessage
+}
+
+type LibraryRecord struct {
+        b         Book
+        available int
+        total     int
+}
+
+type PublicLibrary struct {
+        bookMutex         *sync.Mutex
+        libMutex          *sync.Mutex
+        workingLibrarians int
+        maxLibrarians     int
+        books             map[string]LibraryRecord
+}
+
+type PublicLibraryResponse struct {
+        book *Book
+        err  *LibError
+
+        available  int
+        registered int
+}
+
+func (resp PublicLibraryResponse) GetBook() (fmt.Stringer, error) {
+        return fmt.Stringer(resp.book), resp.err
+}
+
+func (resp PublicLibraryResponse) GetAvailability() (average int, registered int) {
+        return resp.available, resp.registered
+}
+
+func (l *PublicLibrary) AddBookJSON(data []byte) (int, error) {
+        var book Book
+        var total int = 0
+        if err := json.Unmarshal(data, book); err != nil {
+                return 0, err
+        }
+
+        bookRecord, ok := l.books[book.isbn]
+
+        if !ok {
+                newB := &LibraryRecord{b: book, available: 1, total: 1}
+                l.books[book.isbn] = *newB
+                total = newB.total
+        } else {
+                if bookRecord.total >= 4 {
+                        var err LibError = LibError{errorMessage: fmt.Sprintf("Има 4 копия на книга %s", book.isbn)}
+                        total = 4
+                        return total, error(err)
+                } else {
+                        bookRecord.available++
+                        bookRecord.total++
+                        l.books[book.isbn] = bookRecord
+                        total = bookRecord.total
+                }
+        }
+
+        return total, nil
+}
+
+func (l *PublicLibrary) AddBookXML(data []byte) (int, error) {
+        var book Book
+        var total int = 0
+        if err := xml.Unmarshal(data, book); err != nil {
+                return 0, error(err)
+        }
+
+        bookRecord, ok := l.books[book.isbn]
+
+        if !ok {
+                newB := &LibraryRecord{b: book, available: 1, total: 1}
+                l.books[book.isbn] = *newB
+                total = newB.total
+        } else {
+                if bookRecord.total >= 4 {
+                        var err LibError = LibError{errorMessage: fmt.Sprintf("Има 4 копия на книга %s", book.isbn)}
+                        total = 4
+                        return total, error(err)
+                } else {
+                        bookRecord.available++
+                        bookRecord.total++
+                        l.books[book.isbn] = bookRecord
+                        total = bookRecord.total
+                }
+        }
+
+        return total, nil
+}
+
+func (l *PublicLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
+        var reqChanel chan LibraryRequest = make(chan LibraryRequest, 5)
+        var respChanel chan LibraryResponse = make(chan LibraryResponse, 5)
+
+        if l.workingLibrarians == l.maxLibrarians {
+                for l.workingLibrarians == l.maxLibrarians {
+                }
+        }
+
+        go func() {
+                l.libMutex.Lock()
+                l.workingLibrarians++
+                l.libMutex.Unlock()
+
+                for request := range reqChanel {
+                        l.bookMutex.Lock()
+                        b, ok := l.books[request.GetISBN()]
+                        if !ok {
+                                e := &LibError{fmt.Sprintf("Непозната книга %s", request.GetISBN())}
+                                var resp PublicLibraryResponse = PublicLibraryResponse{ nil, e, 0, 0}
+                                respChanel <- resp
+                        } else {
+                                switch request.GetType() {
+                                case 1:
+                                        {
+                                                if b.available == 0 {
+                                                        e := &LibError{fmt.Sprintf("Няма в наличност от книга %s", request.GetISBN())}
+                                                        var resp PublicLibraryResponse = PublicLibraryResponse{ &b.b, e, 0, b.total}
+                                                        respChanel <- resp
+                                                } else {
+                                                        b.available--
+                                                        var resp PublicLibraryResponse = PublicLibraryResponse{ &b.b,nil,b.available,b.total}
+                                                        respChanel <- resp
+                                                        l.books[request.GetISBN()] = b
+                                                }
+
+                                        }
+                                case 2:
+                                        {
+                                                if b.available == b.total {
+                                                        e := &LibError{fmt.Sprintf("Всички копия са налични %s", request.GetISBN())}
+                                                        var resp PublicLibraryResponse = PublicLibraryResponse{&(b.b), e, b.available,b.total}
+                                                        respChanel <- resp
+                                                } else {
+                                                        b.available++
+                                                        l.books[request.GetISBN()] = b
+                                                        var resp PublicLibraryResponse = PublicLibraryResponse{&(b.b),nil,b.available,b.total}
+                                                        respChanel <- resp
+                                                }
+
+                                        }
+                                case 3:
+                                        {
+                                                var resp PublicLibraryResponse = PublicLibraryResponse{&(b.b),nil,b.available,b.total}
+                                                respChanel <- resp
+                                        }
+                                }
+                        }
+                        l.bookMutex.Unlock()
+                }
+
+                close(respChanel)
+
+                l.libMutex.Lock()
+                l.workingLibrarians--
+                l.libMutex.Unlock()
+        }()
+
+        return reqChanel, respChanel
+}
+
+func NewLibrary(librarians int) Library {
+        libM := new(sync.Mutex)
+        bookM := new(sync.Mutex)
+        lib := &PublicLibrary{bookMutex: bookM, libMutex: libM, workingLibrarians: 0, maxLibrarians: librarians, books: make(map[string]LibraryRecord)}
+        return lib
+}
