class PostReply(object):
    '''
    classdocs
    '''
    def __init__(self, board, threadno):
        self.board = board
        self.threadno = threadno

        self.sitekey = "6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc"

        self.captcha2_url = "https://www.google.com/recaptcha/api/fallback?k=" + self.sitekey
        self.captcha2_payload_url = "https://www.google.com/recaptcha/api2/payload"
        self.captcha2_image_base_url = ""
        self.site_ref = "https://boards.4chan.org/"
        self.user_agent = 'Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0'

        self.captcha2_challenge_text = None  # "Select all images with ducks."
        self.captcha2_challenge_id = None

        self.captcha2_image = ""  # Binary image
        self.captcha2_image_filename = "yottu-captcha.jpg"  # TODO don't save the image

        self.captcha2_solution = None  # Array of integers associated to the captcha checkboxes, usually 0-8
        self.captcha2_response = None  # Response the Reply post form wants (the actual solution)

        self.lock = thread.allocate_lock()
        self.dictOutput = None
        self.bp = None

        self.dlog = DebugLog()

    class PostError(Exception):
        def __init__(self, *args, **kwargs):
            Exception.__init__(self, *args, **kwargs)

#    def get_captcha_solution(self):
#        return self.__captcha_solution

    def set_captcha2_solution(self, value):
        # Append checkbox integer values to response array
        try:
            self.captcha2_solution = []
            for i in str(value):
                self.captcha2_solution.append(str(int(i) - 1))
        except ValueError as err:
            self.dlog.excpt(err,
                            msg=">>>in PostReply.set_captcha2_solution()",
                            cn=self.__class__.__name__)
            raise
        except Exception as err:
            self.dlog.excpt(err,
                            msg=">>>in PostReply.set_captcha2_solution()",
                            cn=self.__class__.__name__)

    def _query(self):
        pass

    def get_captcha_challenge(self):
        """
            1. Query captcha url with site key
            2. From the result get
                a) the challenge text
                b) the challenge id
            3. Query payload url with site key and cid and get
                c) the captcha image
        """
        try:
            headers = {'Referer': self.site_ref, 'User-Agent': self.user_agent}
            r = requests.get(self.captcha2_url, headers=headers)

            r.raise_for_status()

            html_content = r.content
            soup = BeautifulSoup(html_content, 'html.parser')

            try:
                self.captcha2_challenge_text = soup.find(
                    "div", {
                        'class': 'rc-imageselect-desc-no-canonical'
                    }).text
            except:
                self.captcha2_challenge_text = soup.find(
                    "div", {
                        'class': 'rc-imageselect-desc'
                    }).text

            self.captcha2_challenge_id = soup.find(
                "div", {
                    'class': 'fbc-imageselect-challenge'
                }).find('input')['value']

            # Get captcha image
            headers = {
                'Referer': self.captcha2_url,
                'User-Agent': self.user_agent
            }
            r = requests.get(self.captcha2_payload_url + '?c=' +
                             self.captcha2_challenge_id + '&k=' + self.sitekey,
                             headers=headers)
            self.captcha2_image = r.content
            #self.save_image(self.captcha2_image_filename)

        except Exception as err:
            self.dlog.excpt(err,
                            msg=">>>in PostReply.get_captcha_challenge()",
                            cn=self.__class__.__name__)
            raise

    def save_image(self, filename):
        """save image to file system"""
        try:

            with open(filename, "w") as f:
                f.write(self.captcha2_image)

        except Exception as err:
            self.dlog.excpt(err,
                            msg=">>>in PostReply.save_image()",
                            cn=self.__class__.__name__)

    def display_captcha(self):

        # Reformat picture to be displayed horizontally
        try:
            TermImage.image_split_h(StringIO(self.captcha2_image),
                                    self.captcha2_image_filename)
        except Exception as err:
            self.dlog.warn(err,
                           msg=">>>in PostReply.display_captcha()",
                           cn=self.__class__.__name__)

        # Overlay the captcha in the terminal
        try:
            TermImage.display(self.captcha2_image_filename)
            return True
        except:
            pass
        # On failure fall back to using the external image viewer
        try:
            TermImage.display_img(self.captcha2_image_filename)
            return False
        except:
            raise

    # FIXME captchav2 update
    def defer(self, time_wait, **kwargs):
        ''' wait for timer to run out before posting '''

        if not self.bp.cfg.get('user.pass.enabled'):
            self.get_response()
            captcha2_response = self.captcha2_response
            self.dlog.msg("Waiting C: " + captcha2_response[:12] + str(kwargs),
                          4)
        self.bp.sb.setStatus("Deferring comment: " + str(time_wait) + "s")

        self.lock.acquire()
        self.dlog.msg("Lock acquired for deferred post " + str(kwargs))

        try:
            while time_wait > 0:
                time.sleep(time_wait)
                # get new lastpost value and see if post needs to be deferred further
                time_wait = self.bp.time_last_posted_thread + 60 - int(
                    time.time())

            if not self.bp.cfg.get('user.pass.enabled'):
                kwargs.update(dict(captcha2_response=captcha2_response))
                self.dlog.msg(
                    "Now posting: C: " + captcha2_response[:12] + str(kwargs),
                    4)
            else:
                self.dlog.msg("Now posting deferred comment", 4)

            rc = self.post(**kwargs)
            if rc != 200:
                self.bp.sb.setStatus("Deferred comment was not posted: " +
                                     str(rc))
        except Exception as err:
            self.bp.sb.setStatus("Deferred: " + str(err))
        finally:
            self.lock.release()

    def get_response(self):

        try:

            headers = {
                'Referer': self.captcha2_url,
                'User-Agent': self.user_agent
            }
            data = {
                'c': self.captcha2_challenge_id,
                'response': self.captcha2_solution
            }
            r = requests.post(self.captcha2_url, headers=headers, data=data)
            html_post = r.content
            soup = BeautifulSoup(html_post, 'html.parser')

        except Exception as err:
            self.dlog.excpt(err,
                            msg=">>>in PostReply.get_response()",
                            cn=self.__class__.__name__)
            raise

        try:
            self.captcha2_response = soup.find(
                "div", {
                    'class': 'fbc-verification-token'
                }).text
        except AttributeError as err:
            self.dlog.warn(
                err,
                msg=
                "Could not get verification token, captcha input error (input: "
                + str(self.captcha2_solution) + ")?",
                cn=self.__class__.__name__)
            raise
        except Exception as err:
            self.dlog.excpt(err,
                            msg=">>>in PostReply.get_response()",
                            cn=self.__class__.__name__)

    def auth(self):
        # Set user.pass.cookie by posting the auth form containing user.pass.token and user.pass.pin

        try:
            token = self.bp.cfg.get('user.pass.token')
            pin = self.bp.cfg.get('user.pass.pin')
            if not token:
                token = self.bp.query_userinput(label="Token: ",
                                                input_type='text')

            if not pin:
                pin = self.bp.query_userinput(label="PIN: ",
                                              input_type='number')

            self.dlog.msg(
                "Authenticating Pass with PIN/Token length: " + str(len(pin)) +
                "/" + str(len(token)), 3)

            data = dict(act='do_login', id=token, pin=pin)

            res = requests.post('https://sys.4chan.org/auth', data=data)

            self.bp.cfg.set('user.pass.cookie', res.cookies['pass_id'])

            if self.bp.cfg.get('config.autosave'):
                self.dlog.msg("Autosaving user.pass.cookie ..")
                self.bp.cfg.writeConfig()

        except KeyError as err:
            self.dlog.excpt(err,
                            msg=">>>in PostReply.auth()",
                            cn=self.__class__.__name__)
            raise PostReply.PostError("Could not authenticate pass token/pin.")
        except Exception as err:
            self.dlog.excpt(err,
                            msg=">>>in PostReply.auth()",
                            cn=self.__class__.__name__)

    def post(self,
             nickname="",
             comment="",
             subject="",
             file_attach="",
             ranger=False,
             captcha2_response=""):
        '''
        subject: not implemented
        file_attach: (/path/to/file.ext) will be uploaded as "file" + extension
        ranger: extract path from ranger's --choosefile file
        '''
        cookies = None
        try:
            if self.bp.cfg.get('user.pass.enabled'):

                if not self.bp.cfg.get('user.pass.cookie'):
                    # get and set new cookie from pass and pin
                    self.auth()
                cookies = dict(pass_id=self.bp.cfg.get('user.pass.cookie'),
                               pass_enabled="1")

            elif not captcha2_response:
                self.get_response()
                captcha2_response = self.captcha2_response

            if nickname == None:
                nickname = ""
            else:
                nickname = u''.join(nickname)

            # Read file / get mime type
            try:
                if file_attach:

                    # extract file path from ranger file and re-assign it
                    if ranger:
                        with open(file_attach, "r") as f:
                            file_attach = f.read()

                    _, file_ext = os.path.splitext(file_attach)
                    filename = "file" + file_ext
                    content_type, _ = mimetypes.guess_type(filename)
                    with open(file_attach, "rb") as f:
                        filedata = f.read()

                    if content_type is None:
                        raise TypeError("Could not detect mime type of file " +
                                        str(filename))
                else:
                    filename = filedata = content_type = ""
            except Exception as err:
                self.dlog.excpt(err,
                                msg=">>>in PostReply.post() -> file_attach",
                                cn=self.__class__.__name__)
                raise

            url = "https://sys.4chan.org/" + self.board + "/post"
            #url = 'http://httpbin.org/status/404'
            #url = "http://localhost/" + self.board + "/post"
            #url = 'http://httpbin.org/post'
            #url = 'http://requestbin.fullcontact.com/1i28ed51'

            values = {
                'MAX_FILE_SIZE': (None, '4194304'),
                'mode': (None, 'regist'),
                # 'pwd' : ('', 'tefF92alij2j'),
                'name': (None, nickname),
                # 'sub' : ('', ''),
                'resto': (None, str(self.threadno)),
                # 'email' : ('', ''),
                'com': (None, comment),
                'g-recaptcha-response': (None, captcha2_response),
                'upfile': (filename, filedata, content_type)
            }

            headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64)'}

            response = requests.post(url,
                                     headers=headers,
                                     files=values,
                                     cookies=cookies)

            # raise exception on error code
            response.raise_for_status()
            if re.search("is_error = \"true\"", response.text):
                perror = "Unknown Error."

                if self.bp.cfg.get('user.pass.cookie'):
                    perror += " user.pass.cookie might be invalid."
                try:
                    perror = re.search(r"Error: ([A-Za-z.,]\w*\s*)+",
                                       response.text).group(0)
                except:
                    if re.search("blocked due to abuse", response.text):
                        perror = "You are range banned ;_;"
                finally:
                    raise PostReply.PostError(perror)

            if response.status_code == 200 and self.dictOutput:
                self.dictOutput.mark(comment)
                self.bp.post_success(int(time.time()))
            else:
                self.dlog.msg("response.status_code: " +
                              str(response.status_code))
                self.dlog.msg("self.dictOutput: " + str(self.dictOutput))

            return response.status_code

        except Exception as err:
            self.dlog.excpt(err,
                            msg=">>>in PostReply.post()",
                            cn=self.__class__.__name__)
            raise