Андон обнови решението на 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
+}