package main

import (
	"github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
	"github.com/ethereum/go-ethereum/swarm/pss"
	"context"
	"bufio"
	"fmt"
	"crypto/ecdsa"
	"os"
	"bytes"
	"time"
	"io/ioutil"
	"encoding/json"
	"github.com/ethereum/go-ethereum/log"
	"strconv"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/p2p/nat"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/node"
	"github.com/ethereum/go-ethereum/p2p"
	"github.com/ethereum/go-ethereum/swarm/storage/feed"
	"github.com/ethereum/go-ethereum/rpc"
	"github.com/ethereum/go-ethereum/swarm"
//	"github.com/ethereum/go-ethereum/swarm/network"
	bzzapi "github.com/ethereum/go-ethereum/swarm/api"

	// XXX: Shouldn't this be bzzclient?
	feedsapi "github.com/ethereum/go-ethereum/swarm/api/client"

)

var (
	// logger
	Log = log.New("hello-pss", "*")
	
	// XXX: Should be multiple, but cheating and only taking parent0
	lastParent = ""

	// Set of seen parent0 swarm hash messages
	SeenSet = make(map[string]bool)
)

// TODO: Ensure node starts in light node so it doesn't eat up a lot of disk space

// XXX: Warning, this is bad design. Should use keystore for this.
func getHexPrivateKey() string {
	privateKey, err := crypto.GenerateKey()
	if err != nil {
		Log.Crit("can't generate private key", err)
	}
	privateKeyBytes := crypto.FromECDSA(privateKey)

	// Debugging and basic key operations
	//publicKey := privateKey.Public()
	//publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
	//if !ok {
	//	log.Crit("error casting public key to ECDSA", err)
	//}
	//publicKeyBytes := crypto.FromECDSAPub(publicKeyECDSA)
	//address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
	//fmt.Println("Private Key: ", hexutil.Encode(privateKeyBytes))
	//fmt.Println("Public Key: ", hexutil.Encode(publicKeyBytes[4:]))
	//fmt.Println("Address: ", address)

	return hexutil.Encode(privateKeyBytes)
}

func getPrivateKeyFromFile(keyfile string) *ecdsa.PrivateKey {
	contents, err := ioutil.ReadFile(keyfile)
	if err != nil {
		log.Crit("Unable to read keyfile", keyfile)
	}
	println(string(contents))
	privateKeyBytes, err := hexutil.Decode(string(contents))
	if err != nil {
		log.Crit("Unable to get private key bytes", err)
	}
	privateKey, err := crypto.ToECDSA(privateKeyBytes)
	if err != nil {
		log.Crit("Unable to get private key", err)
	}

	return privateKey
}

// XXX: This shouldn't be needed
func getp2pConfig(listenaddr string) p2p.Config {
	return p2p.Config{
			ListenAddr: listenaddr,
			MaxPeers:   25,
			NAT:        nat.Any(),
	}
}

// Create a node
func newNode(port int) (*node.Node, error) {
	cfg := &node.DefaultConfig
	cfg.DataDir = fmt.Sprintf("%s%d", ".data_", port)

	// XXX: 	cfg.P2P.ListenAddr = fmt.Sprintf(":%d", port), should work
	if port == 9600 {
		cfg.P2P = getp2pConfig(":30400")
	} else if port == 9601 {
		cfg.P2P = getp2pConfig(":30401")
	} else if port == 9602 {
		cfg.P2P = getp2pConfig(":30402")
	} else {
		log.Crit("Ports be fucked up", "yeah")
	}

	cfg.HTTPPort = port
	cfg.IPCPath = "bzz.ipc"
	//fmt.Printf("Current data directory is %s\n", cfg.DataDir)

	return node.New(cfg)
}

// TODO: How do we know this
// XXX: We can probably cheat with in-memory only by downloading all messages and A is restarting
func seen(hash string) bool {
	return SeenSet[hash]
}

func fetchMessage(hash string) {
	// download from swarm
	httpClient := feedsapi.NewClient("http://localhost:9602") // XXX 9601
	response, _, err := httpClient.DownloadRaw(hash)
	if err != nil {
		fmt.Println("Unable to download raw", err)
		os.Exit(1)
	}
	// Assuming no error, save hash to SeenSet so we don't download again
	// XXX: Edge case because message id of pss message not seen, so calculate again?
	SeenSet[hash] = true

	buf := new(bytes.Buffer)
	buf.ReadFrom(response)
	str := buf.String()
	msg :=  deserialize(str)

	//fmt.Println("***Download raw", str)
	handleMessage(msg)

}



// XXX: Assumes no duplicates
func handleMessage(msg message) {
	// Cheating
	// XXX so much duplication eh
	httpClient := feedsapi.NewClient("http://localhost:9602") // XXX 9601

	// How many cases are there?
	// We have all the dependencies
	// We need to fetch more dependencies
	// We have seen it before
	// We have not seen it before


	// XXX: Edge case, incoming message don't have hash stored already
	// XXX: Hack work around, upload message and check if hash is same
	// Should be possible to figure out hash locally but yeah
	// XXX: Assuming hash is same, which it should be 
	payload := serialize(msg)
	hash, err := httpClient.UploadRaw(bytes.NewReader(payload), int64(len(payload)), false)
	if err != nil {
		fmt.Println("Unable to upload raw", err)
		os.Exit(1)
	}
	//fmt.Println("** Adding hash of message to SeenSet", hash)
	SeenSet[hash] = true

	// Interesting, this seems to unroll and deal with order automatically
	// XXX: Edge cases here because it doesn't save messages, just happy path stack
	parent0 := msg.Parents[0]
	if (parent0 != "") && !seen(parent0) {

		fmt.Printf("[Unmet dependency, downloading: %s]\n", parent0)
		fetchMessage(parent0)

	}
	
	// Only print it if all dependencies are met
	fmt.Println("Alice:", string(msg.Text))
//	fmt.Println("Alice:", string(msg.Text), "- parent0:", string(msg.Parents[0]))
//	fmt.Println("Feed result: ", msg.Text, "- parent0:", msg.Parents[0])

}

func listenForMessages(msgC chan pss.APIMsg) {
	for {
		in := <-msgC
		// XXX: Who is in.key really? want readable public key here
		// XXX: The UX is an illusion

		// XXX: parsing logic should be same for pull from feed
		parsed := deserialize(string(in.Msg))

		//fmt.Println("Alice old:", string(in.Msg))
		// XXX Only one parent
		// TODO: Get all the parents here

		handleMessage(parsed)
		//fmt.Println("\nReceived message", string(in.Msg), "from", fmt.Sprintf("%x", in.Key))
	}
}

// TODO: Error handling if fail
func postToFeed(client *rpc.Client, signer *feed.GenericSigner, receiver string, topic string, data []byte) {
	// For creating manifest, then posting, then finally getting

	// Create a new feed with user and topic.
	f := new(feed.Feed)
	f.User = signer.Address()
	f.Topic, _ = feed.NewTopic("bob", nil)
	query := feed.NewQueryLatest(f, lookup.NoClue)

	// XXX: Ok feeds seems fairly broken
	//httpClient := feedsapi.NewClient("https://swarm-gateways.net")

	// Cheating
	httpClient := feedsapi.NewClient("http://localhost:9602") // XXX 9600

	// local sender alice
	//httpClient := feedsapi.NewClient("http://localhost:9600")

	//XXX doesnt even work
	//httpClient := feedsapi.NewClient("https://swarm-gateways.net")

	// XXX: Post to multiple feeds?

	//fmt.Println("signer Address: ", f.User.Hex())

	request, err := httpClient.GetFeedRequest(query, "")
	if err != nil {
		fmt.Printf("Error retrieving feed status: %s", err.Error())
	}

	request.SetData(data)
	if err = request.Sign(signer); err != nil {
		fmt.Printf("Error signing feed update: %s", err.Error())
	}
	//fmt.Println("*** signed request", request)

	// manifest, err := httpClient.CreateFeedWithManifest(request)
	// if err != nil {
	// 	fmt.Printf("Error getting manifest: %s", manifest)
	// }
	// fmt.Println("MANIFEST:", manifest)
	
	// XXX: What do I want to do with feeds manifest?
	// 567f611190b2758fa625b3be14b2b9becf6f0e8887015b7c40d6cbe0e5fa14aa

	// Success: this works, also from 9601 Bob:
	//  curl 'http://localhost:9600/bzz-feed:/?user=0xBCa21d9c6031b1965a9e0233D9B905d2f10CA259&name=bob'

	// XXX: Why do we need the second argument manifestAddressOrDomain?
	// It's already baked into httpClient and query.
	// Indeed:
	// > You only need to provide either manifestAddressOrDomain or Query to QueryFeed(). Set to "" or nil respectively.
	// response, err := httpClient.QueryFeed(query, "")
	// if err != nil {
	// 	fmt.Println("QueryFeed error", err)
	// }
	// buf := new(bytes.Buffer)
	// buf.ReadFrom(response)
	// feedStr := buf.String()
	// fmt.Println("Feed result: ", feedStr)


	// XXX Want to set level and time?
	// POST /bzz-feed:/?topic=<TOPIC>&user=<USER>&level=<LEVEL>&time=<TIME>&signature=<SIGNATURE>
 
	err = httpClient.UpdateFeed(request)
	if err != nil {
		fmt.Printf("Error updating feed: %s", err.Error())
	}
}

type message struct {
	Text string `json:"text"`
	Parents []string `json:"parents"`
}

// check sign logic bits version etc

// XXX: Lame signature, should be may more compact
func runREPL(client *rpc.Client, signer *feed.GenericSigner, receiver string, topic string) {
	fmt.Println("[I am Alice, and I am ready to send messages.]")
	fmt.Printf("> ")
	// Basic REPL functionality
	scanner := bufio.NewScanner(os.Stdin)	
	for scanner.Scan() {
		input := scanner.Text()
		//sendMessage(input)
		sendMessage(client, signer, receiver, topic, input)
		fmt.Printf("> ")
	}
	if err := scanner.Err(); err != nil {
		fmt.Println("Unable to read input", err)
		os.Exit(1)
	}
}

func mockPassiveREPL() {
	// Poor Bob can only listen to messages, forever and ever
	// Until one day...when he snaps and quits with ctrl-D
	// Bob first shows loyalty, he never speaks, and then he exits
	// Allowing Bob to speak means he'll be less likely to exit
//	for { }
//	fmt.Println("I am Bob or Charlie, and I can't speak right now.")

	fmt.Printf("")
	// Basic REPL functionality
	scanner := bufio.NewScanner(os.Stdin)	
	for scanner.Scan() {
		input := scanner.Text()
		log.Debug("Ignoring input", input)
		//fmt.Println("Echo", input)
		//sendMessage(input)
		//sendMessage(client, signer, receiver, topic, input)
		//fmt.Printf("> ")
	}
	if err := scanner.Err(); err != nil {
		fmt.Println("Unable to read input", err)
		os.Exit(1)
	}
	// Ok maybe this is a bad idea?
}

// Get messages from feed
func pullMessages() {

	// Success: this works, also from 9601 Bob. Replicate with Go API
	//  curl 'http://localhost:9600/bzz-feed:/?user=0xBCa21d9c6031b1965a9e0233D9B905d2f10CA259&name=bob'

	// Querying with local node
	// XXX Maybe this is a bad idea, what about gateway?

	/// Cheating
	httpClient := feedsapi.NewClient("http://localhost:9602") // XXX 9601 
	
	// local receiver bob
	//httpClient := feedsapi.NewClient("http://localhost:9601")

	// XXX: Probably not a great idea, but we need to make sure it is healthy etc
	//httpClient := feedsapi.NewClient("https://swarm-gateways.net")

	// Create a new feed with user and topic.
	f := new(feed.Feed)

	// Alice's dadress
	f.User = common.HexToAddress("0xBCa21d9c6031b1965a9e0233D9B905d2f10CA259")
	f.Topic, _ = feed.NewTopic("bob", nil)
	query := feed.NewQueryLatest(f, lookup.NoClue)

	// Look up feed results
	// XXX: Why do we need the second argument manifestAddressOrDomain?
	// It's already baked into httpClient and query.
	response, err := httpClient.QueryFeed(query, "")
	if err != nil {
		fmt.Println("QueryFeed error", err)
	}
	buf := new(bytes.Buffer)
	buf.ReadFrom(response)
	feedStr := buf.String()

	parsed := deserialize(feedStr)
	handleMessage(parsed)
}

// XXX: This is so sloppy, passing privatekey around
func newService(bzzdir string, bzzport int, privKey *ecdsa.PrivateKey) func(ctx *node.ServiceContext) (node.Service, error) {
	return func(ctx *node.ServiceContext) (node.Service, error) {
		// Create bzzconfig
		// TODO: Setup swarm port
		// XXX: What's difference between Privkey and EnodeKey in Init?
		bzzconfig := bzzapi.NewConfig()
		bzzconfig.Path = bzzdir
		bzzconfig.Port = fmt.Sprintf("%d", bzzport)
		bzzconfig.Init(privKey, privKey)

		return swarm.NewSwarm(bzzconfig, nil)
	}
}

func addPeer(client *rpc.Client, enode string) {
//	fmt.Println("addPeer", enode)
 	var res bool
	err := client.Call(&res, "admin_addPeer", enode)
	if err != nil {
		fmt.Println("Lets also print unable to add peer here", err)
		log.Crit("Unable to add peer", err)
	}
//	fmt.Println("addPeer res", res)
}


func run(port int, privateKey *ecdsa.PrivateKey) {
	// New node
	node, err := newNode(port)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Node failure: %v\n", err)
		os.Exit(1)
	}
	//fmt.Printf("Node: %v\n", node)

	// New Swarm service
	// XXX: Yuck privateKey
	service := newService(node.InstanceDir(), port, privateKey)
	// if err != nil {
	// 	fmt.Fprint(os.Stderr, "Unable to start swarm service: %v\n", err)
	// 	os.Exit(1)
	// }
	//	fmt.Printf("Swarm service: %x\n", service)

	// Register service
	err = node.Register(service)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to register swarm service: %v\n", err)
		os.Exit(1)
	}

	// Start the node
	err = node.Start()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to start node: %v\n", err)
		os.Exit(1)
	}

	// Get RPC Client
	// ipcEndpoint
	client, err := node.Attach()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to attach to client: %v\n", err)
	}

	// TODO: Refactor to have this addpeer workaround in separate function
	// XXX: How to detect/derive this? Right now just grepping enode
	enodeA := "enode://395a074c059143a68473bcf7edb3bae72bc930cfef5c92399401cedd76c493014d29e75ed1833fe45a2c0e04f0e9f9c64bf029c9c0fb646aa23690e945d70193@127.0.0.1:30400"
	enodeB := "enode://f716c8cc7cc6674d8332ae1a3fb7f4776285095dc372c20a508e22e7d0a9c006b1626aab7b45802d99957b86bf1c0c14d9ba91df87528c735751e92dd96fa88f@127.0.0.1:30401"

	// XXX: Broke discovery or something so not connected to many peers, adding some manually as a hack
	// All have caps: ["bzz/8", "hive/8", "pss/2", "stream/8"] and came from standard swarm setup
	//static1 := "enode://058f55a4bfe3ef7c3718ac035cd0bc5ce7646d8acc95930036145a0bcb337eb7769b015cb404201e63e48b261962728554e03c2ffca0a80e857f2c8ad1df02f4@52.232.7.187:30400?discport=0"
	// static2 := "enode://a5d7168024c9992769cf380ffa559a64b4f39a29d468f579559863814eb0ae0ed689ac0871a3a2b4c78b03297485ec322d578281131ef5d5c09a4beb6200a97a@52.232.7.187:30442?discport=0"
	// static3 := "enode://1ffa7651094867d6486ce3ef46d27a052c2cb968b618346c6df7040322c7efc3337547ba85d4cbba32e8b31c42c867202554735c06d4c664b9afada2ed0c4b3c@52.232.7.187:30412?discport=0"

	// Ok, seems like there's an issue with hopCount being exceeded
	// Additionally, unable to geth attach to b receiver specifically
	// Let's try adding intermediate node
	// All it does is...run? Hm.

	// local third node - this has too much stuff in it
	//enodeC := "enode://a87e2c53089904ec916e5b0c06524fa5dbfd69dc31f5446e7937cd1cdbcc61ed6173d17474814a778129ea0ce8b0fdfc4d4b4e9845a82f00358aa548975f6eae@127.0.0.1:30399"

	enodeC := "enode://99c926eaa4276b79b255baaa8562ba124d7b7ecc81fc05e40679d4219ccbf01ec64f9068314cf20372e76d6dca4f02adf5db6570bc6774263fb1a2f7fc890bb6@127.0.0.1:30402"
	
	// open internet
	enodeD := "enode://99c926eaa4276b79b255baaa8562ba124d7b7ecc81fc05e40679d4219ccbf01ec64f9068314cf20372e76d6dca4f02adf5db6570bc6774263fb1a2f7fc890bb6@127.0.0.1:30402"

	// // Consider conditionally adding peers, get who is self.
	// if port == 9600 {
	// 	addPeer(client, enodeB)
	// 	} else if port == 9601 {
	// 		addPeer(client, enodeA)
	// 	}
	// addPeer(client, enodeC)

	addPeer(client, enodeA)
	addPeer(client, enodeB)
	addPeer(client, enodeC)
	addPeer(client, enodeD)

	// addPeer(client, static1)
	// addPeer(client, static2)
	// addPeer(client, static3)

	// // XXX: Eh
	// var res1 bool
	// err = client.Call(&res1, "admin_addPeer", enodeA)
	// if err != nil {
	// 	log.Crit("Unable to add peer", err)
	// }

	// var res2 bool
	// err = client.Call(&res2, "admin_addPeer", enodeB)
	// if err != nil {
	// 	log.Crit("Unable to add peer", err)
	// }
	//fmt.Println("*** added some peers probably ", res1, res2)
	// TODO: admin get peers here?

	// TODO: admin get peers ensure?

	// XXX: More robust health check here
	// Simpler, there should be a stdlib fn for waitHealthy anyway
	time.Sleep(time.Second * 3)

	// Hypothesis for why feed updates aren't spread - kademlia connectivity is bad
	// Test it by measuring it
	// HEALTH CHECK
	//func (k *Kademlia) GetHealthInfo(pp *PeerPot) *Health {
	//network.Kademlia
	// TODO check how do


	// XXX: Not readable
	var nodeinfo p2p.NodeInfo
	err = client.Call(&nodeinfo, "admin_nodeInfo")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to get node info: %v\n", err)
	}

	var baseaddr string
	err = client.Call(&baseaddr, "pss_baseAddr")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to get base addr: %v\n", err)
	}
	//fmt.Println("baseAddr", baseaddr)

	var pubkey string
	err = client.Call(&pubkey, "pss_getPublicKey")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to get pss public key: %v\n", err)
	}
	//fmt.Println("PublicKey", pubkey)

	// XXX: Same with baseaddr
	// 0xd5ac92dd8f593ea7aabf5cfdb35d4d29d87316ffe3ae081750054168e147eb42
	bobBaseAddr := "0xb208b76c916d5eb84c118c0076b35828f0728a416537786f4515dd6608c4874d"
	//fmt.Println("BobbaseAddr PSS", bobBaseAddr)

	// XXX: This is separate from node generated key, so want to save this contacts or so
	// f(alice/bob.key, 9600/9601), not confirmed if it is stable if port changes
	// alice: 0x04c56131d8ded90e79b76b97f26e8fc032597886ff68ab6557f91c4bf1ae46eab94415c6df30bb6479cf40f811977bb2b237787f5b807d97191f7a994a558633e0
	// bob: 0x04cbd6b75038f2d1e4e8e2754ffadecaaa8d2fdbbb29311dc82a8e1880fce4576f86e3d87ab360bcdde1aaf9a01a2cf232be95684a1152a735ccb4200495e4145c

	var topic string
	err = client.Call(&topic, "pss_stringToTopic", "bob")

	bobPubKey := "0x04cbd6b75038f2d1e4e8e2754ffadecaaa8d2fdbbb29311dc82a8e1880fce4576f86e3d87ab360bcdde1aaf9a01a2cf232be95684a1152a735ccb4200495e4145c"
	receiver := bobPubKey
	//fmt.Println("BobPublicKey PSS", bobPubKey)

	// XXX: I don't understand how baseAddr and public key interact
	// XXX: I also don't understand why you need to register public key
	err = client.Call(nil, "pss_setPeerPublicKey", bobPubKey, topic, bobBaseAddr)

	msgC := make(chan pss.APIMsg)
	// Nope, everyone gets to listen on that topic, also maybe it should be same?
	// Does it matter for feeds?
	// XXX: Let'ss try
	sub, err := client.Subscribe(context.Background(), "pss", msgC, "receive", topic, false, false)

	// Only Bob gets to listen
	// if port == 9601 {
	// 	sub, err := client.Subscribe(context.Background(), "pss", msgC, "receive", topic, false, false)
	// 	if err != nil {
	// 		fmt.Println("Error subscribing to topic", err)
	// 	}
	// 	defer sub.Unsubscribe()
	// }

	// XXX: Hack to make sure ready state
	time.Sleep(time.Second * 3)

	signer := feed.NewGenericSigner(privateKey)

	// XXX: Hacky
	// TODO: Replace with REPL-like functionality
	if port == 9600 {

		// NOTE: We assume here we are ready to actually send messages, so we REPL here
		// XXX: Only running REPL for Alice Sender for now
		runREPL(client, signer, receiver, topic)
	} else if port == 9601 {
		fmt.Println("[I am Bob, and I am ready to receive messages.]")

		fmt.Println("[Syncing data...]")
		pullMessages()
		fmt.Println("[Synced up, listening for new mesages.]")
		go listenForMessages(msgC)
		mockPassiveREPL()
	} else if port == 9602 {
		fmt.Println("[I am Charlie, I'm just chilling here.]")
		mockPassiveREPL()
	} else {
		fmt.Println("*** I don't know who you are")
		os.Exit(1)
	}

	fmt.Printf("All operations successfully completed.\n")

	// Teardown
	sub.Unsubscribe()
	client.Close()
	node.Stop()
}

func init() {
	// NOTE: taken from ethereum-samples
	hs := log.StreamHandler(os.Stderr, log.TerminalFormat(true))
	loglevel := log.LvlInfo
	// TODO: Setup flag and -v option
	// if *verbose {
	// 	loglevel = log.LvlTrace
	// }
	loglevel = log.LvlDebug //trace
	//loglevel = log.LvlTrace //trace

	hf := log.LvlFilterHandler(loglevel, hs)
	h := log.CallerFileHandler(hf)
	log.Root().SetHandler(h)
}

// TODO: The swarm hash should match up with message ID
// How does this impact design?

// XXX: Ensure signature, also probably better with client as context but meh
// TODO: Message should include its parents
func sendMessage(client *rpc.Client, signer *feed.GenericSigner, receiver string, topic string, input string) {

	// Keeping track of last parent, only one
	msg := message{Text: input, Parents: []string{lastParent}}
	payload := serialize(msg)

	// 1. Send via PSS
	err := client.Call(nil, "pss_sendAsym", receiver, topic, common.ToHex(payload))
	if err != nil {
		fmt.Println("Error sending message through RPC client", err)
		os.Exit(1)
	}

	// 2. Upload to swarm to get hash for message dependency
	// XXX: Might be more elegant way of doing this with manifests etc

	// XXX: In so many places...
	// TODO: Replace with 9600 once end to end
	httpClient := feedsapi.NewClient("http://localhost:9602") // XXX 9600

	hash, err := httpClient.UploadRaw(bytes.NewReader(payload), int64(len(payload)), false)
	if err != nil {
		fmt.Println("Unable to upload raw", err)
		os.Exit(1)
	}
	// Now that we have hash, save this as lastParent
	lastParent = hash
	//fmt.Println("***last Parent", lastParent)
	
	// 3. Also post to feed
	// XXX: Currently hardcoded to plaintext name, could be hash of two pubkeys e.g.
	// TODO: If any errors with this, show this
	postToFeed(client, signer, receiver, topic, payload)
}

func serialize(msg message) []byte {
	//msg := &message{Text: "hi", Parents: []string{"foo", "bar"}}
	data, err := json.Marshal(msg)
	if err != nil {
		fmt.Println("Unable to marshal into JSON", err)
		os.Exit(1)
	}
	return data
}

// func serialize2(msg message) string {
// 	//msg := &message{Text: "hi", Parents: []string{"foo", "bar"}}
// 	payload, err := json.Marshal(msg)
// 	if err != nil {
// 		fmt.Println("Unable to marshal into JSON", err)
// 		os.Exit(1)
// 	}
// 	//XXX shouldnt this be byte ?!
// 	strJSON := string(payload) 
// 	//fmt.Println("json payload", strJSON)
// 	return strJSON
// }

func deserialize(strJSON string) message {
	msg := message{}
	json.Unmarshal([]byte(strJSON), &msg)
	// fmt.Println(msg2)
	return msg
}

func main() {
	fmt.Println("[Hello PSS/Feeds!]")
	fmt.Println("[Setting up node and connecting to the network...]")

	// XXX Lets use already running node because why not
	// TODO: Replace with 9600 once end to end
	// XXX: Forgot did we use this somewhere?
	//httpClient := feedsapi.NewClient("http://localhost:9602") // XXX 9600

	// Ok, now we need to populate parent and fetch it
	// To do this, we need a chunk that we upload
	// Lets try basic swarm up and include that

	// TODO: Then, integrate feed and update there too
	// Cool, here ATM.
	// Then we probably need some message deps
	// TODO: As Alice we want to do a basic Feed post
	// TODO: Then As Bob we want to do a basic Feed get pull, at startup or so
	// Possibly ability to toggle this
	// XXX: Actually how connected is this to the rest of the network? Who will store it?
	// Create feed first

	// TODO: Bad CLI design, use golang flags
	// TODO: Pull this out to separate parseArgs function
	args := os.Args[1:]
	if len(args) == 1 {
		if args[0] == "new" {
			// TODO: Use keystore or something more sane
			privateKey := getHexPrivateKey()
			ioutil.WriteFile("new.key", []byte(privateKey), 0644)
			log.Crit("Thanks for the fish, your private key is now insecurely stored in new.key", args)
		} else {
			log.Crit("Unknown argument, please use 'new' or two arguments (keyfile and port)", args)
		}
	} else if len(args) == 2 {
		keyfile := args[0]
		portArg := args[1]
		// XXX error handling
		privateKey := getPrivateKeyFromFile(keyfile)
		port, err := strconv.Atoi(portArg)
		if err != nil {
			log.Crit("Unable to parse port argument", portArg)
		}
		// Start engines
		run(port, privateKey)
	} else {
		log.Crit("Wrong number of arguments, should be one (new) or two (keyfile and port)", args)
	}
}