import io
from urllib.parse import urlencode

from multidict import MultiDict, MultiDictProxy

from . import hdrs, multipart, payload
from .helpers import guess_filename

__all__ = ('FormData',)


class FormData:
    """Helper class for multipart/form-data and
    application/x-www-form-urlencoded body generation."""

    def __init__(self, fields=(), quote_fields=True, charset=None):
        self._writer = multipart.MultipartWriter('form-data')
        self._fields = []
        self._is_multipart = False
        self._quote_fields = quote_fields
        self._charset = charset

        if isinstance(fields, dict):
            fields = list(fields.items())
        elif not isinstance(fields, (list, tuple)):
            fields = (fields,)
        self.add_fields(*fields)

    @property
    def is_multipart(self):
        return self._is_multipart

    def add_field(self, name, value, *, content_type=None, filename=None,
                  content_transfer_encoding=None):

        if isinstance(value, io.IOBase):
            self._is_multipart = True
        elif isinstance(value, (bytes, bytearray, memoryview)):
            if filename is None and content_transfer_encoding is None:
                filename = name

        type_options = MultiDict({'name': name})
        if filename is not None and not isinstance(filename, str):
            raise TypeError('filename must be an instance of str. '
                            'Got: %s' % filename)
        if filename is None and isinstance(value, io.IOBase):
            filename = guess_filename(value, name)
        if filename is not None:
            type_options['filename'] = filename
            self._is_multipart = True

        headers = {}
        if content_type is not None:
            if not isinstance(content_type, str):
                raise TypeError('content_type must be an instance of str. '
                                'Got: %s' % content_type)
            headers[hdrs.CONTENT_TYPE] = content_type
            self._is_multipart = True
        if content_transfer_encoding is not None:
            if not isinstance(content_transfer_encoding, str):
                raise TypeError('content_transfer_encoding must be an instance'
                                ' of str. Got: %s' % content_transfer_encoding)
            headers[hdrs.CONTENT_TRANSFER_ENCODING] = content_transfer_encoding
            self._is_multipart = True

        self._fields.append((type_options, headers, value))

    def add_fields(self, *fields):
        to_add = list(fields)

        while to_add:
            rec = to_add.pop(0)

            if isinstance(rec, io.IOBase):
                k = guess_filename(rec, 'unknown')
                self.add_field(k, rec)

            elif isinstance(rec, (MultiDictProxy, MultiDict)):
                to_add.extend(rec.items())

            elif isinstance(rec, (list, tuple)) and len(rec) == 2:
                k, fp = rec
                self.add_field(k, fp)

            else:
                raise TypeError('Only io.IOBase, multidict and (name, file) '
                                'pairs allowed, use .add_field() for passing '
                                'more complex parameters, got {!r}'
                                .format(rec))

    def _gen_form_urlencoded(self):
        # form data (x-www-form-urlencoded)
        data = []
        for type_options, _, value in self._fields:
            data.append((type_options['name'], value))

        charset = self._charset if self._charset is not None else 'utf-8'
        return payload.BytesPayload(
            urlencode(data, doseq=True).encode(charset),
            content_type='application/x-www-form-urlencoded')

    def _gen_form_data(self):
        """Encode a list of fields using the multipart/form-data MIME format"""
        for dispparams, headers, value in self._fields:
            try:
                if hdrs.CONTENT_TYPE in headers:
                    part = payload.get_payload(
                        value, content_type=headers[hdrs.CONTENT_TYPE],
                        headers=headers, encoding=self._charset)
                else:
                    part = payload.get_payload(
                        value, headers=headers, encoding=self._charset)
            except Exception as exc:
                raise TypeError(
                    'Can not serialize value type: %r\n '
                    'headers: %r\n value: %r' % (
                        type(value), headers, value)) from exc

            if dispparams:
                part.set_content_disposition(
                    'form-data', quote_fields=self._quote_fields, **dispparams
                )
                # FIXME cgi.FieldStorage doesn't likes body parts with
                # Content-Length which were sent via chunked transfer encoding
                part.headers.pop(hdrs.CONTENT_LENGTH, None)

            self._writer.append_payload(part)

        return self._writer

    def __call__(self):
        if self._is_multipart:
            return self._gen_form_data()
        else:
            return self._gen_form_urlencoded()

aiohttp/formdata.py
import io
from urllib.parse import urlencode

from multidict import MultiDict, MultiDictProxy

from . import hdrs, multipart, payload
from .helpers import guess_filename

__all__ = ('FormData',)


class FormData:
    """Helper class for multipart/form-data and
    application/x-www-form-urlencoded body generation."""

    def __init__(self, fields=(), quote_fields=True, charset=None):
        self._writer = multipart.MultipartWriter('form-data')
        self._fields = []
        self._is_multipart = False
        self._quote_fields = quote_fields
        self._charset = charset

        if isinstance(fields, dict):
            fields = list(fields.items())
        elif not isinstance(fields, (list, tuple)):
            fields = (fields,)
        self.add_fields(*fields)

    @property
    def is_multipart(self):
        return self._is_multipart

    def add_field(self, name, value, *, content_type=None, filename=None,
                  content_transfer_encoding=None):

        if isinstance(value, io.IOBase):
            self._is_multipart = True
        elif isinstance(value, (bytes, bytearray, memoryview)):
            if filename is None and content_transfer_encoding is None:
                filename = name

        type_options = MultiDict({'name': name})
        if filename is not None and not isinstance(filename, str):
            raise TypeError('filename must be an instance of str. '
                            'Got: %s' % filename)
        if filename is None and isinstance(value, io.IOBase):
            filename = guess_filename(value, name)
        if filename is not None:
            type_options['filename'] = filename
            self._is_multipart = True

        headers = {}
        if content_type is not None:
            if not isinstance(content_type, str):
                raise TypeError('content_type must be an instance of str. '
                                'Got: %s' % content_type)
            headers[hdrs.CONTENT_TYPE] = content_type
            self._is_multipart = True
        if content_transfer_encoding is not None:
            if not isinstance(content_transfer_encoding, str):
                raise TypeError('content_transfer_encoding must be an instance'
                                ' of str. Got: %s' % content_transfer_encoding)
            headers[hdrs.CONTENT_TRANSFER_ENCODING] = content_transfer_encoding
            self._is_multipart = True

        self._fields.append((type_options, headers, value))

    def add_fields(self, *fields):
        to_add = list(fields)

        while to_add:
            rec = to_add.pop(0)

            if isinstance(rec, io.IOBase):
                k = guess_filename(rec, 'unknown')
                self.add_field(k, rec)

            elif isinstance(rec, (MultiDictProxy, MultiDict)):
                to_add.extend(rec.items())

            elif isinstance(rec, (list, tuple)) and len(rec) == 2:
                k, fp = rec
                self.add_field(k, fp)

            else:
                raise TypeError('Only io.IOBase, multidict and (name, file) '
                                'pairs allowed, use .add_field() for passing '
                                'more complex parameters, got {!r}'
                                .format(rec))

    def _gen_form_urlencoded(self):
        # form data (x-www-form-urlencoded)
        data = []
        for type_options, _, value in self._fields:
            data.append((type_options['name'], value))

        charset = self._charset if self._charset is not None else 'utf-8'
        return payload.BytesPayload(
            urlencode(data, doseq=True, encoding=charset).encode(),
            content_type='application/x-www-form-urlencoded')

    def _gen_form_data(self):
        """Encode a list of fields using the multipart/form-data MIME format"""
        for dispparams, headers, value in self._fields:
            try:
                if hdrs.CONTENT_TYPE in headers:
                    part = payload.get_payload(
                        value, content_type=headers[hdrs.CONTENT_TYPE],
                        headers=headers, encoding=self._charset)
                else:
                    part = payload.get_payload(
                        value, headers=headers, encoding=self._charset)
            except Exception as exc:
                raise TypeError(
                    'Can not serialize value type: %r\n '
                    'headers: %r\n value: %r' % (
                        type(value), headers, value)) from exc

            if dispparams:
                part.set_content_disposition(
                    'form-data', quote_fields=self._quote_fields, **dispparams
                )
                # FIXME cgi.FieldStorage doesn't likes body parts with
                # Content-Length which were sent via chunked transfer encoding
                part.headers.pop(hdrs.CONTENT_LENGTH, None)

            self._writer.append_payload(part)

        return self._writer

    def __call__(self):
        if self._is_multipart:
            return self._gen_form_data()
        else:
            return self._gen_form_urlencoded()

aiohttp/formdata.py
diff --git a/aiohttp/formdata.py b/aiohttp/formdata.py
index e6fb1f9b7bc..2a141dc6bf5 100644
--- a/aiohttp/formdata.py
+++ b/aiohttp/formdata.py
@@ -96,7 +96,7 @@ def _gen_form_urlencoded(self):
 
         charset = self._charset if self._charset is not None else 'utf-8'
         return payload.BytesPayload(
-            urlencode(data, doseq=True).encode(charset),
+            urlencode(data, doseq=True, encoding=charset).encode(),
             content_type='application/x-www-form-urlencoded')
 
     def _gen_form_data(self):

Encoding is always UTF-8 in POST data
## Long story short

I'm doing a `POST` request via `client.post`:

```
data = aiohttp.FormData({
            'FindText': name,
        }, charset='windows-1251')

client.post(base_url, params={'RowFrom': offset}, data=data)
```

where `name` contains some none-latin text (`'хан'`)

## Expected behaviour

POST data should contain: `FindText=%D5%E0%ED`

## Actual behaviour

`FindText=%D1%85%D0%B0%D0%BD'`

## Steps to reproduce

Looking through the code of `formdata.py:99`

```
urlencode(data, doseq=True).encode(charset),
```

I noticed, that `data` is urlencoded in UTF-8 first and then encoded to `windows-1251` (and that has no effect on `%D1...`).

For now, I just manually do in my code:

```
data = urlencode({
            'FindText': name,
        }, encoding='windows-1251')
```

And I get the string that I need.

Is it a bug? Or am I doing it wrong?

## Your environment

```
Python 3.6.0 (default, Jan 16 2017, 12:12:55) 
[GCC 6.3.1 20170109] on linux
---
aiohttp==2.0.3
```

