# 158. Read N Characters Given Read4 II - Call multiple times
# Hard
# 318814FavoriteShare
# Given a file and assume that you can only read the file using a given method read4, implement a method read to read n characters. Your method read may be called multiple times.
 
# Method read4:
# The API read4 reads 4 consecutive characters from the file, then writes those characters into the buffer array buf.
# The return value is the number of actual characters read.
# Note that read4() has its own file pointer, much like FILE *fp in C.
# Definition of read4:
#     Parameter:  char[] buf
#     Returns:    int

# Note: buf[] is destination not source, the results from read4 will be copied to buf[]
# Below is a high level example of how read4 works:
# File file("abcdefghijk"); // File is "abcdefghijk", initially file pointer (fp) points to 'a'
# char[] buf = new char[4]; // Create buffer with enough space to store characters
# read4(buf); // read4 returns 4. Now buf = "abcd", fp points to 'e'
# read4(buf); // read4 returns 4. Now buf = "efgh", fp points to 'i'
# read4(buf); // read4 returns 3. Now buf = "ijk", fp points to end of file
 
# Method read:
# By using the read4 method, implement the method read that reads n characters from the file and store it in the buffer array buf. Consider that you cannot manipulate the file directly.
# The return value is the number of actual characters read.
# Definition of read:
#     Parameters: char[] buf, int n
#     Returns:    int

# Note: buf[] is destination not source, you will need to write the results to buf[]
 
# Example 1:
# File file("abc");
# Solution sol;
# // Assume buf is allocated and guaranteed to have enough space for storing all characters from the file.
# sol.read(buf, 1); // After calling your read method, buf should contain "a". We read a total of 1 character from the file, so return 1.
# sol.read(buf, 2); // Now buf should contain "bc". We read a total of 2 characters from the file, so return 2.
# sol.read(buf, 1); // We have reached the end of file, no more characters can be read. So return 0.
# Example 2:
# File file("abc");
# Solution sol;
# sol.read(buf, 4); // After calling your read method, buf should contain "abc". We read a total of 3 characters from the file, so return 3.
# sol.read(buf, 1); // We have reached the end of file, no more characters can be read. So return 0.
 
# Note:
# 1.  Consider that you cannot manipulate the file directly, the file is only accesible for read4 but not for read.
# 2.  The read function may be called multiple times.
# 3.  Please remember to RESET your class variables declared in Solution, as static/class variables are persisted across multiple test cases. Please see here for more details.
# 4.  You may assume the destination buffer array, buf, is guaranteed to have enough space for storing n characters.
# 5.  It is guaranteed that in a given test case the same buffer buf is called by read.
"""
The read4 API is already defined for you.

    @param buf, a list of characters
    @return an integer
    def read4(buf):

# Below is an example of how the read4 API can be called.
file = File("abcdefghijk") # File is "abcdefghijk", initially file pointer (fp) points to 'a'
buf = [' '] * 4 # Create buffer with enough space to store characters
read4(buf) # read4 returns 4. Now buf = ['a','b','c','d'], fp points to 'e'
read4(buf) # read4 returns 4. Now buf = ['e','f','g','h'], fp points to 'i'
read4(buf) # read4 returns 3. Now buf = ['i','j','k',...], fp points to end of file
"""


class Solution:
    def __init__(self):
        self.n_left = 0
        self.buffer = [""]
            

    def read(self, buf, n):
        """
        :type buf: Destination buffer (List[str])
        :type n: Number of characters to read (int)
        :rtype: The number of actual characters read (int)
        """
        #print(self.n_left,self.buffer)
        if n <= self.n_left:
            self.n_left -= n
            for i in range(n):
                buf[i] = self.buffer[i]
            self.buffer = self.buffer[n:]
            return n
        n_total = self.n_left
        for i in range(n_total):
            buf[i] = self.buffer[i]
        while n_total < n:
            temp = [""]*4
            n_actual = read4(temp)
            if n_actual == 0: break
            for i in range(n_total,n_total+n_actual):
                buf[i] = temp.pop(0)
            n_total += n_actual
        if n_total < n:
            self.n_left = 0
            self.buffer = [""]
            return n_total
        
        self.n_left = n_total - n
        #print(n_read,n_actual,n_read - n)
        #print(buf)
        self.buffer = buf[n:n_total]
        return n
