Антоан обнови решението на 05.12.2015 02:23 (преди над 2 години)
+package main
+
+import (
+ "fmt"
+ "errors"
+ "encoding/json"
+ "encoding/xml"
+ "time"
+)
+
+type Library interface {
+ AddBookJSON(data []byte) (int, error)
+ AddBookXML(data []byte) (int, error)
+ Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
+}
+
+type Book struct {
+ Title string `xml:"title"`
+ Isbn string `xml:"isbn,attr"`
+ Author AuthorName `xml:"author"`
+ Ratings []int `xml:"ratings>rating"`
+}
+
+type AuthorName struct {
+ First_name string `xml:"first_name"`
+ Last_name string `xml:"last_name"`
+}
+
+type MyLibrary struct {
+ booksMap map[string]*Book
+ booksRegisteredMap map[string]int
+ booksAvailabilityMap map[string]int
+ librariansCount int
+}
+
+func (book Book) String() string {
+ return fmt.Sprintf("[%s] %s от %s %s",
+ book.Isbn, book.Title, book.Author.First_name, book.Author.Last_name)
+}
+
+func (lib MyLibrary) AddBookJSON(data []byte) (int, error) {
+ annon := func(book *Book, bytes []byte) error {
+ err := json.Unmarshal(bytes, &book)
+ return err
+ }
+
+ bookCount, err := lib.AddBook(data, annon)
+
+ return bookCount, err
+}
+
+func (lib MyLibrary) AddBookXML(data []byte) (int, error) {
+
+ annon := func(book *Book, bytes []byte) error {
+ return xml.Unmarshal(bytes, &book)
+ }
+ bookCount, err := lib.AddBook(data, annon)
+
+ return bookCount, err
+}
+
+func (lib MyLibrary) AddBook(bytes []byte, unmarshaller func(*Book, [] byte) error) (int, error) {
+ var book Book
+ unmarshaller(&book, bytes)
+
+ if _, ok := lib.booksRegisteredMap[book.Isbn]; !ok {
+ lib.booksRegisteredMap[book.Isbn] = 0
+ lib.booksAvailabilityMap[book.Isbn] = 0
+ }
+
+ if lib.booksRegisteredMap[book.Isbn] < 4 {
+ lib.booksMap[book.Isbn] = &book
+ lib.booksRegisteredMap[book.Isbn] += 1
+ lib.booksAvailabilityMap[book.Isbn] += 1
+ } else {
+ return 4, errors.New(fmt.Sprintf("Има 4 копия на книга %s", book.Isbn))
+ }
+
+ return lib.booksRegisteredMap[book.Isbn], nil
+}
+
+func (lib MyLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
+ writeOnlyChannel := make(chan LibraryRequest, lib.librariansCount)
+ readOnlyChannel := make(chan LibraryResponse, lib.librariansCount)
+
+ go func() {
+ for {
+ select {
+ case req := <-writeOnlyChannel:
+ reqType := req.GetType()
+ isbn := req.GetISBN()
+ err := 0
+
+ if (reqType == 1) { // borrow book
+ val, ok := lib.booksAvailabilityMap[isbn];
+
+ if !ok {
+ err = 1
+ } else if val == 0 {
+ err = 3
+ } else {
+ lib.booksAvailabilityMap[isbn] -= 1
+ }
+ } else if reqType == 2 { //returning book
+ if _, ok := lib.booksMap[isbn]; !ok {
+ err = 1
+ } else if lib.booksRegisteredMap[isbn] == lib.booksAvailabilityMap[isbn] {
+ err = 2
+ } else if lib.booksAvailabilityMap[isbn] < lib.booksRegisteredMap[isbn] {
+ lib.booksAvailabilityMap[isbn] += 1
+ }
+ } else if reqType == 3 { // get availability info
+ if _, ok := lib.booksMap[isbn]; !ok {
+ err = 1
+ }
+ }
+
+ response := &MyLibraryResponse{Isbn: isbn, Type: reqType, Error: err, MyBook: lib.booksMap[isbn], Registered: lib.booksRegisteredMap[isbn], Available: lib.booksAvailabilityMap[isbn]}
+ readOnlyChannel <- response
+
+ time.Sleep(100 * time.Millisecond)
+ case <- time.After(1 * time.Second):
+ break;
+ }
+ }
+ } ()
+
+
+ return writeOnlyChannel, readOnlyChannel
+}
+
+type LibraryRequest interface {
+ GetType() int
+ GetISBN() string
+}
+
+type MyLibraryRequest struct {
+ Type int
+ Isbn string
+}
+
+func (req MyLibraryRequest) GetType() int {
+ return req.Type
+}
+
+func (req MyLibraryRequest) GetISBN() string {
+ return req.Isbn
+}
+
+type LibraryResponse interface {
+ GetBook() (fmt.Stringer, error)
+ GetAvailability() (available int, registered int)
+}
+
+type MyLibraryResponse struct {
+ MyBook *Book
+ Available int
+ Registered int
+ Error int // 1-unknown book, 2-have all copies, 3-no books available
+ Type int
+ Isbn string
+}
+
+func (res MyLibraryResponse) GetBook() (fmt.Stringer, error) {
+
+ switch res.Error {
+ case 1:
+ return nil, errors.New(fmt.Sprintf("Непозната книга %s", res.Isbn))
+ case 2:
+ return nil, errors.New(fmt.Sprintf("Всички копия са налични %s", res.Isbn))
+ case 3:
+ return nil, errors.New(fmt.Sprintf("Няма наличност на книга %s", res.Isbn))
+ }
+
+ return res.MyBook, nil
+}
+
+func (res MyLibraryResponse) GetAvailability() (available int, registered int) {
+ return res.Available, res.Registered
+}
+
+func NewLibrary(librarians int) Library {
+ lib := &MyLibrary{librariansCount: librarians, booksAvailabilityMap: make(map[string]int), booksMap: make(map[string]*Book), booksRegisteredMap: make(map[string]int)}
+ return lib
+}