#include <string.h>
#include <stdio.h>
#include "afpfs-ng/map_def.h"
#include "afpfs-ng/dsi.h"
#include "afpfs-ng/afp.h"

int afp_status_header(char * text, int * len) 
{
	int pos;
	memset(text,0,*len);

	pos=snprintf(text,*len,"AFPFS Version: %s\n"
		"UAMs compiled in: %s\n",
		AFPFS_VERSION,
		get_uam_names_list());
	*len-=pos;
	if (*len==0) return -1;
	return pos;
}

static void print_volume_status(struct afp_volume * v, 
	char * text,int * pos_p, int * len)
{
	struct afp_server * s = v->server;
	int pos = *pos_p;
	unsigned int fl = v->extra_flags;

	pos+=snprintf(text+pos,*len-pos,
		"    Volume %s, id %d, attribs 0x%x mounted: %s%s\n",
		v->volume_name_printable,v->volid,
		v->attributes,
		(v->mounted==AFP_VOLUME_MOUNTED) ? v->mountpoint:"No",
		((v->mounted==AFP_VOLUME_MOUNTED) && (volume_is_readonly(v))) ?
			" (read only)":"");

	if (v->mounted==AFP_VOLUME_MOUNTED) {
		pos+=snprintf(text+pos,*len-pos,
		"        did cache stats: %llu miss, %llu hit, %llu expired, %llu force removal\n        uid/gid mapping: %s (%d/%d)\n",
		v->did_cache_stats.misses, v->did_cache_stats.hits,
		v->did_cache_stats.expired, 
		v->did_cache_stats.force_removed,
		get_mapping_name(v),
		s->server_uid,s->server_gid);
		pos+=snprintf(text+pos,*len-pos,
		"        Unix permissions: %s",
			(v->extra_flags&VOLUME_EXTRA_FLAGS_VOL_SUPPORTS_UNIX)?
				"Yes":"No");

		if (s->server_type==AFPFS_SERVER_TYPE_NETATALK) {
			pos+=snprintf(text+pos,*len-pos,
			", Netatalk permissions broken: ");
			
			if (fl&VOLUME_EXTRA_FLAGS_VOL_CHMOD_KNOWN)
				if (fl&VOLUME_EXTRA_FLAGS_VOL_CHMOD_BROKEN)
					pos+=snprintf(text+pos,*len-pos,
						"Yes\n");
				else
					pos+=snprintf(text+pos,*len-pos,
						"No\n");
			else 
				pos+=snprintf(text+pos,*len-pos,
					"Unknown\n");
		}
	}
	*pos_p=pos;
}

int afp_status_server(struct afp_server * s, char * text, int * len) 
{
	int j;
	struct afp_volume *v;
	char signature_string[AFP_SIGNATURE_LEN*2+1];
	int pos=0;
	int firsttime=0;
	struct dsi_request * request;
	char ip_addr[64];

	memset(text,0,*len);

	if (s==NULL) {
		pos+=snprintf(text+pos,*len-pos,
			"Not connected to any servers\n");
		goto out;
	}
		
	for (j=0;j<AFP_SIGNATURE_LEN;j++)
		sprintf(signature_string+(j*2),"%02x",
			(unsigned int) ((char) s->signature[j]));

	switch(s->used_address->ai_family) 
	{
		case AF_INET6:
       	    inet_ntop(AF_INET6, 
						&(((struct sockaddr_in6 *)s->used_address->ai_addr)->sin6_addr),
       		            ip_addr, INET6_ADDRSTRLEN);
       		break;
       		case AF_INET:
       	    inet_ntop(AF_INET, 
						&(((struct sockaddr_in *)s->used_address->ai_addr)->sin_addr),
       		            ip_addr, INET6_ADDRSTRLEN);
       		break;
			default:
			snprintf(ip_addr, 23, "unknown address family");
			break;
	}
	ip_addr[63] = '\0';
	
	pos+=snprintf(text+pos,*len-pos,
		"Server %s\n"
		"    connection: %s:%d %s\n"
		"    using AFP version: %s\n",
		s->server_name_printable,
		ip_addr, ntohs(s->used_address->ai_protocol),
		(s->connect_state==SERVER_STATE_DISCONNECTED ? 
		"(disconnected)" : "(active)"),
		s->using_version->av_name
	);

	pos+=snprintf(text+pos,*len-pos,
		"    server UAMs: ");

	for (j=1;j<0x100;j<<=1) {
		if (j & s->supported_uams) {
			if (firsttime!=0) 
				pos+=snprintf(text+pos,*len-pos,
					", ");
			if (j==s->using_uam)
				pos+=snprintf(text+pos,*len-pos,
					"%s (used)",
					uam_bitmap_to_string(j));
			else
				pos+=snprintf(text+pos,*len-pos,
					"%s",
					uam_bitmap_to_string(j));
			firsttime=1;
		}
	};

	pos+=snprintf(text+pos,*len-pos,
		"\n    login message: %s\n"
		"    type: %s",
		s->loginmesg, s->machine_type);


	pos+=snprintf(text+pos,*len-pos,
		"\n"
		"    signature: %s\n"
		"    transmit delay: %ums\n"
		"    quantums: %u(tx) %u(rx)\n"
		"    last request id: %d in queue: %llu\n",
	signature_string,
	s->tx_delay,
	s->tx_quantum, s->rx_quantum,
	s->lastrequestid,s->stats.requests_pending);

	for (request=s->command_requests;request;request=request->next) {
		pos+=snprintf(text+pos,*len-pos,
			"         request %d, %s\n",
			request->requestid, afp_get_command_name(request->subcommand)); 
	}

	pos+=snprintf(text+pos,*len-pos,
		"    transfer: %llu(rx) %llu(tx)\n"
		"    runt packets: %llu\n",
	s->stats.rx_bytes,s->stats.tx_bytes,
	s->stats.runt_packets);

	if (*len==0) goto out;

	for (j=0;j<s->num_volumes;j++) {
		v=&s->volumes[j];
		print_volume_status(v,text,&pos,len);
		pos+=snprintf(text+pos,*len-pos,"\n");
	}

out:
	*len-=pos;
	return pos;

}
