/*
 * Copyright 2013 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.netty.handler.codec.dns;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.StringUtil;

import java.nio.charset.Charset;
import java.util.List;

/**
 * DnsQueryEncoder accepts {@link DnsQuery} and encodes to {@link ByteBuf}. This
 * class also contains methods for encoding parts of DnsQuery's such as the
 * header and questions.
 */
@ChannelHandler.Sharable
public class DnsQueryEncoder extends MessageToMessageEncoder<DnsQuery> {

    @Override
    protected void encode(ChannelHandlerContext ctx, DnsQuery query, List<Object> out) throws Exception {
        ByteBuf buf = ctx.alloc().buffer();
        encodeHeader(query.header(), buf);
        List<DnsQuestion> questions = query.questions();
        for (DnsQuestion question : questions) {
            encodeQuestion(question, CharsetUtil.UTF_8, buf);
        }
        out.add(new DatagramPacket(buf, query.recipient(), null));
    }

    /**
     * Encodes the information in a {@link DnsHeader} and writes it to the
     * specified {@link ByteBuf}. The header is always 12 bytes long.
     *
     * @param header
     *            the query header being encoded
     * @param buf
     *            the buffer the encoded data should be written to
     */
    private static void encodeHeader(DnsHeader header, ByteBuf buf) {
        buf.writeShort(header.id());
        int flags = 0;
        flags |= header.type() << 15;
        flags |= header.opcode() << 14;
        flags |= header.isRecursionDesired() ? 1 << 8 : 0;
        buf.writeShort(flags);
        buf.writeShort(header.questionCount());
        buf.writeShort(header.answerCount()); // Must be 0
        buf.writeShort(header.authorityResourceCount()); // Must be 0
        buf.writeShort(header.additionalResourceCount()); // Must be 0
    }

    /**
     * Encodes the information in a {@link DnsQuestion} and writes it to the
     * specified {@link ByteBuf}.
     *
     * @param question
     *            the question being encoded
     * @param charset
     *            charset names are encoded in
     * @param buf
     *            the buffer the encoded data should be written to
     */
    private static void encodeQuestion(DnsQuestion question, Charset charset, ByteBuf buf) {
        String[] parts = StringUtil.split(question.name(), '.');
        for (String part: parts) {
            buf.writeByte(part.length());
            buf.writeBytes(part.getBytes(charset));
        }
        buf.writeByte(0); // marks end of name field
        buf.writeShort(question.type().intValue());
        buf.writeShort(question.dnsClass().intValue());
    }
}

@@ -1676,12 +1676,156 @@
 il.U
-TF_8
+S_ASCII, buf);%0A        %7D%0A        for (DnsResource resource: query.additionalResources()) %7B%0A            encodeResource(resource, CharsetUtil.US_ASCII
 , bu
@@ -2604,23 +2604,23 @@
 teShort(
-header.
+0); // 
 answerCo
@@ -2622,33 +2622,16 @@
 werCount
-()); // Must be 0
 %0A       
@@ -2646,23 +2646,23 @@
 teShort(
-header.
+0); // 
 authorit
@@ -2675,33 +2675,16 @@
 rceCount
-()); // Must be 0
 %0A       
@@ -2737,21 +2737,8 @@
 ());
- // Must be 0
 %0A   
@@ -3202,202 +3202,576 @@
     
-String%5B%5D parts = StringUtil.split(question.name(), '.'
+encodeName(question.name(), charset, buf);%0A        buf.writeShort(question.type().intValue());%0A        buf.writeShort(question.dnsClass().intValue()
 );%0A    
+%7D%0A%0A
     
-for (String part: parts) %7B%0A            buf.writeByte(part.length());%0A            buf.writeBytes(part.getBytes(charset)
+private static void encodeResource(DnsResource resource, Charset charset, ByteBuf buf) %7B%0A        encodeName(resource.name(), charset, buf);%0A%0A        buf.writeShort(resource.type().intValue());%0A        buf.writeShort(resource.dnsClass().intValue());%0A        buf.writeInt((int) resource.timeToLive());%0A%0A        ByteBuf content = resource.content();%0A        int contentLen = content.readableBytes(
 );%0A
+%0A
         
 %7D%0A  
@@ -3770,170 +3770,549 @@
     
-%7D%0A        buf.writeByte(0); // marks end of name field%0A        buf.writeShort(question.type().intValue());%0A        buf.writeShort(question.dnsClass().intValue()
+buf.writeShort(contentLen);%0A        buf.writeBytes(content, content.readerIndex(), contentLen);%0A    %7D%0A%0A    private static void encodeName(String name, Charset charset, ByteBuf buf) %7B%0A        String%5B%5D parts = StringUtil.split(name, '.');%0A        for (String part: parts) %7B%0A            final int partLen = part.length();%0A            if (partLen == 0) %7B%0A                continue;%0A            %7D%0A            buf.writeByte(partLen);%0A            buf.writeBytes(part.getBytes(charset));%0A        %7D%0A        buf.writeByte(0
 );
+ // marks end of name field
 %0A   

Add EDNS support to DnsQueryEncoder